Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Mailing Lists -> Oracle-L -> Multithreaded Direct Path OCI Problems in Oracle 8i

Multithreaded Direct Path OCI Problems in Oracle 8i

From: MacGregor, Ian A. <ian_at_SLAC.Stanford.EDU>
Date: Tue, 09 Jul 2002 10:59:57 -0800
Message-ID: <F001.00492A77.20020709105957@fatcity.com>


I have written before about our project to record channel archive data in Oracle. Channel archive data has to do with the status of the accelerator. We just started taking data on a klystron design which gloms together eight of the amplifiers to begin to meet the power needs for the Next Linear Collider.

We have a multi-threaded OCI direct path program which works quite well under Oracle 9i, but returns a 1403 error under Oracle 8i. The respective versions are 9.0.1.3 and 8.1.6.3. If we can get this program to work, it will be used at various high -energy physics labs around the world. One of the most interested labs is BESSY, Berliner Elektronenspeicherring-Geselschaft fur Synchrotronstralung mbH. They are not ready to implement 9i yet and want us to get it running against 8i. When I say us, I mean the developers. I've written lots of C programs, but none were multithreaded and nearly all were Pro*C.

There are two files involved the first sets up the environment.



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

#include "oci.h"

#include "oracle_defs.h"
#include "oci_defs.h"

/*
#ifdef DEBUG

*/

GLOBAL int db_init(char *instance,

                   ALL_OCI_HANDLES *all_oci_handles,
                   ALL_OCI_HANDLES *thread_oci_handles)
{

    int sts;

#ifdef DEBUG

    fprintf(stderr, "instance = %s\n", instance);
#endif

    memset(all_oci_handles, 0, sizeof(ALL_OCI_HANDLES));

#ifdef ORACLE_9I_OR_HIGHER

    sts = OCIInitialize((ub4) OCI_THREADED, (dvoid *) 0,

        (dvoid * (*) (dvoid *, size_t)) 0,
        (dvoid * (*) (dvoid *, dvoid *, size_t)) 0,
        (void (*)(dvoid *, dvoid *)) 0 );
    if (sts != SUCCESS)
    {
        fprintf(stderr, "Error returned from OCIInitialize = %d\n", sts);
        return(ERROR);

    }
#else

    sts = OCIInitialize((ub4) OCI_OBJECT, (dvoid *) 0,

        (dvoid * (*) (dvoid *, size_t)) 0,
        (dvoid * (*) (dvoid *, dvoid *, size_t)) 0,
        (void (*)(dvoid *, dvoid *)) 0 );
    if (sts != SUCCESS)
    {
        fprintf(stderr, "Error returned from OCIInitialize = %d\n", sts);
        return(ERROR);

    }
#endif

    sts = OCIEnvInit( (OCIEnv **) &all_oci_handles->EnvH, OCI_DEFAULT,

        (size_t) 0, (dvoid **) 0 );
    if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIEnvInit = %d\n", sts);
        return(ERROR);

    }

#ifdef ORACLE_9I_OR_HIGHER

    sts = OCIEnvInit( (OCIEnv **) &thread_oci_handles->EnvH, OCI_DEFAULT,

        (size_t) 0, (dvoid **) 0 );
    if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIEnvInit = %d\n", sts);
        return(ERROR);

    }
#endif

    sts = OCIHandleAlloc( (dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->ErrH,

        OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0);     if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIHandleAlloc #1 = %d\n", sts);
        return(ERROR);

    }

#ifdef ORACLE_9I_OR_HIGHER

    sts = OCIHandleAlloc( (dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->ErrH,

        OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0);     if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIHandleAlloc #1 = %d\n", sts);
        return(ERROR);

    }
#endif

    /* Server contexts.

#ifdef ORACLE_9I_OR_HIGHER

    sts = OCIHandleAlloc( (dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->SrvH,

        OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0);     if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIHandleAlloc #2 = %d\n", sts);
        return(ERROR);

    }
#endif

    sts = OCIHandleAlloc( (dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->SvcH,

        OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0);     if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIHandleAlloc #3 = %d\n", sts);
        return(ERROR);

    }

#ifdef ORACLE_9I_OR_HIGHER

    sts = OCIHandleAlloc( (dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->SvcH,

        OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0);     if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIHandleAlloc #3 = %d\n", sts);
        return(ERROR);

    }
#endif

    sts = OCIServerAttach(all_oci_handles->SrvH, all_oci_handles->ErrH, (text *)instance,

        strlen(instance), 0);
    if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIServerAttach = %d\n", sts);
        return(ERROR);

    }

#ifdef ORACLE_9I_OR_HIGHER

    sts = OCIServerAttach(thread_oci_handles->SrvH, thread_oci_handles->ErrH, (text *)instance,

        strlen(instance), 0);
    if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIServerAttach = %d\n", sts);
        return(ERROR);

    }
#endif

    /* Set attribute context in the service context.

#ifdef ORACLE_9I_OR_HIGHER

    sts = OCIAttrSet( (dvoid *) thread_oci_handles->SvcH, OCI_HTYPE_SVCCTX,

        (dvoid *) thread_oci_handles->SrvH, (ub4) 0, OCI_ATTR_SERVER,
        (OCIError *) thread_oci_handles->ErrH);
    if (sts != SUCCESS)
    {
        fprintf(stderr, "Error returned from OCIAttrSet = %d\n", sts);
        return(ERROR);

    }
#endif

    sts = OCIHandleAlloc((dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->SesH,

        (ub4) OCI_HTYPE_SESSION, (size_t) 0,
        (dvoid **) 0);

    if (sts != SUCCESS)
    {
        fprintf(stderr, "Error returned from OCIHandleAlloc #4 = %d\n", sts);
        return(ERROR);

    }

#ifdef ORACLE_9I_OR_HIGHER

    sts = OCIHandleAlloc((dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->SesH,

        (ub4) OCI_HTYPE_SESSION, (size_t) 0,
        (dvoid **) 0);

    if (sts != SUCCESS)
    {
        fprintf(stderr, "Error returned from OCIHandleAlloc #4 = %d\n", sts);
        return(ERROR);

    }
#endif

    sts = OCIHandleAlloc((dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->SelectStmt,

        (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0);     if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIHandleAlloc #5 = %d\n", sts);
        return(ERROR);

    }

#ifdef ORACLE_9I_OR_HIGHER

    sts = OCIHandleAlloc((dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->SelectStmt,

        (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0);     if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIHandleAlloc #5 = %d\n", sts);
        return(ERROR);

    }
#endif

    sts = OCIHandleAlloc((dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->InsertStmt,

        (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0);     if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIHandleAlloc #6 = %d\n", sts);
        return(ERROR);

    }

#ifdef ORACLE_9I_OR_HIGHER

    sts = OCIHandleAlloc((dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->InsertStmt,

        (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0);     if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIHandleAlloc #6 = %d\n", sts);
        return(ERROR);

    }
#endif

    sts = OCIHandleAlloc((dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->UpdateStmt,

        (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0);     if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIHandleAlloc #6 = %d\n", sts);
        return(ERROR);

    }

#ifdef ORACLE_9I_OR_HIGHER

    sts = OCIHandleAlloc((dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->UpdateStmt,

        (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0);     if (sts != SUCCESS)
    {

        fprintf(stderr, "Error returned from OCIHandleAlloc #6 = %d\n", sts);
        return(ERROR);

    }
#endif

    return(SUCCESS);
}



Note the different calls to OCIInitialize. If we use OCI_THREADED instead of OCI_OBJECT the 8.1.6 database it leads to trouble.

Here is the program which does the work

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

#include "oci.h"

#include "oracle_defs.h"
#include "oci_defs.h"

GLOBAL int float_table_init(ALL_OCI_HANDLES *all_oci_handles,

                            int direct_path_buf_rows)
{

    int sts;
    int i;
    int pos;
    int stat;

    char float_table_name[] = "arch_data_f";     char float_table_schema_name[] = "";

    char float_table_col_names[FLOAT_TABLE_NCOL_TBL][MAX_NAME_COL_LEN + 1] =

        {"pv_id",
         "value",
         "timestamp",
         "nanosecs",
         "stat",
         "sevr",
         "ostat"};

    int float_table_col_exttyp[FLOAT_TABLE_NCOL_TBL] =
        {SQLT_INT,
         SQLT_FLT,
         SQLT_DAT,
         SQLT_INT,
         SQLT_INT,
         SQLT_INT,
         SQLT_INT};

    int float_table_maxlen_fld[FLOAT_TABLE_NCOL_TBL] =
         {38,
          15,
          7,
          9,
          8,
          8,
          16};

    int float_table_precision[FLOAT_TABLE_NCOL_TBL] =
         {38,
          15,
          0,
          9,
          8,
          8,
          16};

    int float_table_scale[FLOAT_TABLE_NCOL_TBL] =
         {0,
          5,
          0,
          0,
          0,
          0,
          0};

    TABLE_INFO float_table_info;

    COL_INFO *colp;

    FLD_INFO *fldp;

    OCIParam *colDesc;

    ub2 num_cols;
    ub2 exttyp_col;
    ub2 csid_col;

    ub1 prec_col;

    sb1 scale_col;

    ub4 maxlen_fld;

    ub4 buf_size = 300000;
    ub4 num_rows;

    text Error[512];
    sb4 ErrorCode;

    /***Logic begins */

    num_rows = direct_path_buf_rows;

    /* Step 1 (performing the OCI initialization) has been done previously.

        Step 2 is to allocate a direct path context handle and set the
        attributes.
    ------------------------------------------------------------------------ */
    sts = OCIHandleAlloc((dvoid *) all_oci_handles->EnvH,
        (dvoid **) &all_oci_handles->FloatTableDirPathCtxH,
        (ub4) OCI_HTYPE_DIRPATH_CTX, (size_t) 0, (dvoid **) 0);
    if (sts != SUCCESS)
    {
        fprintf(stderr, "Error returned from OCIHandleAlloc #1 = %d\n", sts);
        OCIErrorGet(all_oci_handles->ErrH, (ub4) 1, (text *) NULL,
            &ErrorCode, Error, (ub4) sizeof(Error),
            OCI_HTYPE_ERROR);
        fprintf(stderr, "Error: %s\n", Error);
        return(ERROR);

    }
    sts = OCIAttrSet((dvoid *) all_oci_handles->FloatTableDirPathCtxH, (ub4) OCI_HTYPE_DIRPATH_CTX,
                     (dvoid *) &buf_size,
                     (ub4) 0,
                     (ub4) OCI_ATTR_BUF_SIZE, all_oci_handles->ErrH);
    if (sts != SUCCESS)
    {
        fprintf(stderr, "Error returned from OCIAttrSet #1 = %d\n", sts);
        return(ERROR);

    }

#ifdef ORACLE_9I_OR_HIGHER

    sts = OCIAttrSet((dvoid *) all_oci_handles->FloatTableDirPathCtxH, (ub4) OCI_HTYPE_DIRPATH_CTX,
                     (dvoid *) &num_rows,
                     (ub4) 0,
                     (ub4) OCI_ATTR_NUM_ROWS, all_oci_handles->ErrH);
    if (sts != SUCCESS)
    {
        fprintf(stderr, "Error returned from OCIAttrSet #2 = %d\n", sts);
        OCIErrorGet(all_oci_handles->ErrH, (ub4) 1, (text *) NULL,
            &ErrorCode, Error, (ub4) sizeof(Error),
            OCI_HTYPE_ERROR);
        fprintf(stderr, "Error: %s\n", Error);

        return(ERROR);

    }
#endif

    /* Fill in the float_table_info data structure, which describes the

       table to be loaded using the direct path API.  This data structure
       includes information about each column of the table.
    --------------------------------------------------------------------- */
    strcpy(float_table_info.name_tbl, float_table_name);

    float_table_info.ncol_tbl = FLOAT_TABLE_NCOL_TBL;

    float_table_info.col_tbl = (COL_INFO *) malloc(FLOAT_TABLE_NCOL_TBL *

        sizeof(COL_INFO));
    if (float_table_info.col_tbl == NULL)     {

        fprintf(stderr, "Unable to allocate float_table_info.col_tbl\n");
        return(ERROR);

    }

    float_table_info.fld_tbl = (FLD_INFO *) malloc(FLOAT_TABLE_NCOL_TBL *

        sizeof(FLD_INFO));
    if (float_table_info.fld_tbl == NULL)     {

        fprintf(stderr, "Unable to allocate float_table_info.fld_tbl\n");
        return(ERROR);

    }

    for (i = 0, colp = float_table_info.col_tbl, fldp = float_table_info.fld_tbl;

         i < FLOAT_TABLE_NCOL_TBL; i++, colp++, fldp++)     {

        colp->id_col = 0;
        strcpy(colp->name_col, float_table_col_names[i]);
        colp->exttyp_col = float_table_col_exttyp[i];
        strcpy(colp->datemask_col, "");
        colp->prec_col = float_table_precision[i];
        colp->scale_col = float_table_scale[i];
        colp->csid_col = 0;

        fldp->maxlen_fld = float_table_maxlen_fld[i];
    }

    /* Step 3 is to supply the name of the object (in this case, the

       name of a table) to be loaded.

#ifdef ORACLE_9I_OR_HIGHER

    sts = OCIAttrSet((dvoid *) all_oci_handles->FloatTableDirPathCtxH, (ub4) OCI_HTYPE_DIRPATH_CTX,
                     (dvoid *) float_table_schema_name,
                     (ub4) strlen((const char *) float_table_schema_name),
                     (ub4) OCI_ATTR_SCHEMA_NAME, all_oci_handles->ErrH);
    if (sts != SUCCESS)
    {
        fprintf(stderr, "Error returned from OCIAttrSet #4 = %d\n", sts);
        return(ERROR);

    }
#endif

    /* Step 4 is to describe the external data types of the table columns.

    sts = OCIAttrGet((dvoid *) all_oci_handles->FloatTableDirPathCtxH, OCI_HTYPE_DIRPATH_CTX,
                     (dvoid *) &all_oci_handles->FloatTableColLstDesc,
                     (ub4 *) 0, OCI_ATTR_LIST_COLUMNS, all_oci_handles->ErrH);
    if (sts != SUCCESS)
    {
        fprintf(stderr, "Error returned from OCIAttrGet #1 = %d\n", sts);
        return(ERROR);

    }

    for (i = 0, pos = 1, colp = float_table_info.col_tbl, fldp = float_table_info.fld_tbl;

         i < FLOAT_TABLE_NCOL_TBL; i++, pos++, colp++, fldp++)     {

        sts = OCIParamGet((dvoid *) all_oci_handles->FloatTableColLstDesc, (ub4) OCI_DTYPE_PARAM,
                          (dvoid *) all_oci_handles->ErrH,
                          (dvoid **) &colDesc, pos);
        if (sts != SUCCESS)
        {
            fprintf(stderr, "Error returned from OCIParamGet = %d\n", sts);
            return(ERROR);
        }

        colp->id_col = i;

        sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM,
                         (dvoid *) colp->name_col,
                         (ub4) strlen((const char *)colp->name_col),
                         (ub4) OCI_ATTR_NAME, all_oci_handles->ErrH);
        if (sts != SUCCESS)
        {
            fprintf(stderr, "Error returned from OCIAttrSet #6 = %d\n", sts);
            return(ERROR);
        }

        exttyp_col = (ub2) colp->exttyp_col;

        sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM,
                         (dvoid *) &exttyp_col,
                         (ub4) 0, (ub4) OCI_ATTR_DATA_TYPE, all_oci_handles->ErrH);
        if (sts != SUCCESS)
        {
            fprintf(stderr, "Error returned from OCIAttrSet #7 = %d\n", sts);
            return(ERROR);
        }

        maxlen_fld = (ub4) fldp->maxlen_fld;

        sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM,
                         (dvoid *) &maxlen_fld,
                         (ub4) 0, (ub4) OCI_ATTR_DATA_SIZE, all_oci_handles->ErrH);
        if (sts != SUCCESS)
        {
            fprintf(stderr, "Error returned from OCIAttrSet #8 = %d\n", sts);
            return(ERROR);
        }

        if (strlen(colp->datemask_col) > 0)
        {
            sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM,
                             (dvoid *) colp->datemask_col,
                             (ub4) strlen((const char *) colp->datemask_col),
                             (ub4) OCI_ATTR_DATEFORMAT, all_oci_handles->ErrH);
            if (sts != SUCCESS)
            {
                fprintf(stderr, "Error returned from OCIAttrSet #9 = %d\n", sts);
                return(ERROR);
            }
        }

        if (colp->prec_col)
        {
            prec_col = (ub1) colp->prec_col;

            sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM,
                             (dvoid *) &prec_col,
                             (ub4) 0, (ub4) OCI_ATTR_PRECISION, all_oci_handles->ErrH);
            if (sts != SUCCESS)
            {
                fprintf(stderr, "Error returned from OCIAttrSet #10 = %d\n", sts);
                return(ERROR);
            }
        }

        if (colp->scale_col)
        {
            scale_col = (sb1) colp->scale_col;

            sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM,
                             (dvoid *) &scale_col,
                             (ub4) 0, (ub4) OCI_ATTR_SCALE, all_oci_handles->ErrH);
            if (sts != SUCCESS)
            {
                fprintf(stderr, "Error returned from OCIAttrSet #11 = %d\n", sts);
                return(ERROR);
            }
        }

        if (colp->csid_col)
        {
            csid_col = (ub2) colp->csid_col;

            sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM,
                             (dvoid *) &csid_col,
                             (ub4) 0, (ub4) OCI_ATTR_CHARSET_ID, all_oci_handles->ErrH);
            if (sts != SUCCESS)
            {
                fprintf(stderr, "Error returned from OCIAttrSet #12 = %d\n", sts);
                return(ERROR);
            }
        }

        sts = OCIDescriptorFree((dvoid *) colDesc, OCI_DTYPE_PARAM);
        if (sts != SUCCESS)
        {
            fprintf(stderr, "Error returned from OCIDescriptorFree = %d\n", sts);
            return(ERROR);
        }

    }

    free(float_table_info.col_tbl);
    free(float_table_info.fld_tbl);

#ifdef ORACLE_9I_OR_HIGHER

    sts = lock_table(all_oci_handles, float_table_name);     if (sts != SUCCESS)
    {

        fprintf(stderr, "error return from lock_table\n");
        return(sts);

    }
#endif

    /* Step 5 is to prepare the direct path interface.

        /***TESTING
        return(ERROR);
        */
        exit(0);

    }

    sts = commit_trans(all_oci_handles);     if (sts != SUCCESS)
    {

        fprintf(stderr, "error return from commit_trans\n");
        return(sts);

    }

    /* Step 6 is to allocate a column array.

    /* Step 7 is to allocate a direct path stream.

    /* Get the number of rows and columns in the column array just allocated.

    sts = OCIAttrGet(all_oci_handles->FloatTableColArrayH, (ub4) OCI_HTYPE_DIRPATH_COLUMN_ARRAY,

                     &all_oci_handles->FloatTableNumCols,
                     0, OCI_ATTR_NUM_COLS, all_oci_handles->ErrH);
    if (sts != SUCCESS)
    {
        fprintf(stderr, "Error returned from OCIAttrGet #3 = %d\n", sts);
        return(ERROR);

    }

#ifdef DEBUG

    fprintf(stderr, "FloatTableNumRows = %d\n", all_oci_handles->FloatTableNumRows);     fprintf(stderr, "FloatTableNumCols = %d\n", all_oci_handles->FloatTableNumCols);
#endif

    return(SUCCESS);
}



The program has the main thread doing direct path inserts and some DML operations while a second thread using another connection does some updates. As I said it works well in 9i, but if we multithread the 8i version a 1403 error occurs on the call to OCIHANDLEALLOC with the argument OCI_HTYPE_DIRPATH_CTX

I imagine we are on the hemorrhaging edge doing this with 8i. Is anybody doing anything similar. Have you been successful with 8i. If so what version. I tried to relate the problem to an OCI bug, but was could not. If it would run under the latest 8.1.7 release, that might be acceptable to the folks in Germany. To be fair it ain't the Germans that are insistent, but the project leader here.

Ian MacGregor
Stanford Linear Accelerator Center
ian_at_SLAC

-- 
Please see the official ORACLE-L FAQ: http://www.orafaq.com
-- 
Author: MacGregor, Ian A.
  INET: ian_at_SLAC.Stanford.EDU

Fat City Network Services    -- (858) 538-5051  FAX: (858) 538-5051
San Diego, California        -- Public Internet access / Mailing Lists
--------------------------------------------------------------------
To REMOVE yourself from this mailing list, send an E-Mail message
to: ListGuru_at_fatcity.com (note EXACT spelling of 'ListGuru') and in
the message BODY, include a line containing: UNSUB ORACLE-L
(or the name of mailing list you want to be removed from).  You may
also send the HELP command for other information (like subscribing).
Received on Tue Jul 09 2002 - 13:59:57 CDT

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US