| GSI | HADES@GSI | HADES@Catania | HADES@Cracow | HADES@Giessen | HADES@Santiago | HADES@TUM | CERN |

HADES Logo

Client-side File I/O into/from Oracle tables

Program description by Ilse Koenig Ilse Koenig
GSI September 18, 2000


| class documentation | Computing | CVS | Oracle | ROOT |

Content:





Introduction


Oracle provides very limited support for loading data from a file into a table especially on LINUX. The Oracle Loader accepts only files on a server disk and therefore cannot be used by normal users.
The package UTL_FILE can read and write files on external disks, but the directories must be set in the initialization file of the Oracle server. The server does not check the access rights to these directories. The lack of flexibitilty and the security problem was the motivation to write a C++ program (using the Oracle C/C++ precompiler for embedded SQL) for the read/write of files on client directories. It uses the ROOT interpreter as user interface (but does not use any HYDRA classes).

The program reads data organized column-wise and fills them into a new (temporary) or already existing table. One line in the file corresponds to one row in the table.
Inside the program, tables can be created and dropped again when not needed anymore. Filling the data into a temporary table has some advantages: The file might contain errors and might spoil data in an already existing table. Before using other tools (WEBDB, TOAD, SQLPLUS) the inserts must be committed and it might be difficult to delete them later again. Once the data are in Oracle one can use SQL to check and maybe manipulate the data before inserting them into the permanent table(s).
The program supports the insert of single rows 'by hand' and also the update of rows (in temporary tables only).

Loading data from a file is the main aspect of the program. But it can also write the content of tables or views to a client-side file. It provides support for conditions and ordering of the results.

This documentation shows mainly how to use the program on the ROOT interpreter. See the class documentation for a complete list of classes and their functions.

Downloaded of the program: orautil.tar.gz

Starting the Program


To start the program load the library libOraUtil.so into ROOT.
Then instantiate an object of type HDbFileIo and connect to Oracle (asks for the password!).
   HDbFileIo io;
   io.connectDb("ikoenig","db-hades.gsi.de");
or
   io.connectDb("hades");
The (default) database "db-hades.gsi.de" is the actual HADES production database.
User "hades" is only allowed to read data, not to create a table or to insert data.
Users can only create new tables in their own account. The insert of data is allowed into all tables owned by this user and also into all tables, the user has the insert privilege granted for.
The connection to Oracle is closed by
   io.closeDbConn();

Loading data from file into an Oracle table


To load data from a file into an Oracle table first open a file in i/o mode "IN".
   io.openFile("/u/ilse/analtest/macros/OraProg/test.txt","IN");
To separate a line in the file into different columns, the delimiter between columns must be eventually set (default: white space) or the text-delimiter (default: single quote), which encapsulates in the file a text column containing internally column delimiters (see Parameters for I/O how to change the default settings).

Loading data into a new (temporary) table

A default table name is generated by concatenating "TMP_" and the filename, skipping the directory and the file extension (in this example "TMP_TEST").
If the function
   io.readFile();
is directly called after opening a file, the table with this name will be filled. Normally this table does not exist and must be created. The first line to be inserted defines the number of columns. The column names are COL1, COL2, ... and the default type of all columns is VARCHAR2(80).

One can also create a new table specifying the name of the table, the column names and the column types individually. This is especially necessary when the new table should have more or less columns than the first line to be inserted or if a column must be longer than 80 characters.
   HDbTable* table=io.setTableName("tmp_test1");
returns a pointer to a form (object of class HDbTable), where columns can be inserted. It checks also if the table with this name exits already. Suppose the table does exist, then there are two possibilities to set the columns and eventually their individual types: A column can be removed from the list with the function
   void HDbTable::removeColumn(const char*);
and all columns by
   void HDbTable::clearColumns();
To see the actual table definition call
   table->show();
The table is created automatically, when the function HDbFileIo::readFile() is called. It first shows the actual table definition and asks for confirmation to create the table. Then the lines in the file are read and the data inserted into the table: After all lines have been read, the program shows the number of rows inserted into the table. The data are not yet committed (unless the flag autoCommit was set explicitly to kTRUE before). One can print the content of the table on the screen (or a file) before committing or rolling back the transaction.
When an error occurs during insert, the transaction is rolled back (and also all former ones which where not yet committed). But the table still exists.
Remark: Because Oracle launches an automatic commit when creating or dropping a table, you are asked to confirm a commit when you open a new file or drop a table. When you leave the program without committing before, you are also asked to do so. To see the data in the table call
   io.printResult();

In case the table is very long you might want to set a condition before printing, e.g.
   HDbTable* table=io.getCurTable();
   table->setCondition("rownum < 50");
   io.printResult();
   table->clearCondition();


Single rows can be inserted into the table, e.g.
   io.makeInsert("*","'XYZ',11,1.1,'Some text'");
   io.makeInsert("col1,col4","'XX','Some text'");

The wildcard "*" instead of the list of columns can be used when values are provided for all columns in the table (in correct order!). One row or several rows can be updated in a temporary table e.g. io.makeUpdate("col2=11, col3=1.1","col1='XYZ'")
The first parameter is the assign string for the columns, the second is the condition for the rows to be updated.
WARNING: With an empty condition or a condition which is always true, all rows in the table will be updated!

Tables created inside the program can be dropped before closing the actual Oracle session. Once the connection is closed and opened again, this is not allowed anymore within this program. To show all created tables call
   io.showTemporaryTables();
and to drop them
   io.dropTemporaryTables();
or to drop a single table
   io.dropTemporaryTable("tableName")
(Asks for confirmation before dropping a table.)

The file is not closed in the function readFile() to allow subsequent partial reads of the file without re-open. The file is automatically closed when one opens a new file or leaves the program, or one calls explicitly the function closeFile()

Loading data into an existing table

Inserting data into an existing table is not much different from inserting data into a new table. One sets only the name of the table. The funtion
  HDbTable* HDbFileIo::setTableName(const char*) returns a pointer to a table form containing already all columns and their types of the existing table. In case the file contains the columns in a different order than in the table, one removes all columns and sets them again in the order of the file (or maybe only part of the columns inserting NULL values in the other columns). Before the first insert, the SQL statement is shown and must be confirmed.
Example:
   io.openFile("test1.txt","IN");
   HDbTable* table=io.setTableName("tmp_test");
   table->show();
   table->clearColumns();
   table->setColumns("col4, col3, col2, col1");
   io.readFile();

Single inserts 'by hand' are possible, but no updates.

Writing data from an Oracle table or view to a file


Set the table name (or owner.tablename).
   HDbTable* table=io.setTableName("mdc_ana.mdc_loc_history");
   table->show();

Optional are the specification of
To see the result on the screen call
   io.printResult();
or open a file and write the result to the file.
   io.openFile("test3.txt","out");
   io.writeFile();

The file can be opened in "out" or "app" mode. The program will not automatically overwrite an existing file opend in "out" mode, but will ask for confirmation to do so.

The following functions support also the query from views which require a date or run set in advance:
   HDbFileIo::setSearchDate(const char* time="sysdate")
   HDbFileIo::setRun(const char* daqFile)

Examples:
   HDbTable* table=io.setTableName("mdc_ana.mdc_loc_at_run");
   io.setRun("n99_089.hld");
   io.printResult();

   HDbTable* table=io.setTableName("mdc_ana.mdcrawstruct_at_date");
   io.setSearchDate("01-NOV-1999");
   io.printResult();


Parameters for I/O


The following parameters are used in the I/O program (class HDbFileIo): To see the actual setting call
   io.showSettings();