DB2-Admin

 view release on metacpan or  search on metacpan

Admin.xs  view on Meta::CPAN

                if (len >= sizeof(entries[counter].location_entry)) {
                    croak("%s string '%s' too long - maximum %d bytes supported\n",
                          type_, val,
                          sizeof(entries[counter].location_entry));
                }
                strcpy(entries[counter].location_entry, val);
                /* warn("DEBUG: path element %d of %s is '%s'\n", */
                /* counter, type_, entries[counter].location_entry); */
            } else {
                croak("Array element %d for %s is not a string", counter, type_);
            }
        }
    } else if (SvPOK(info_)) {
        char   *val;
        void   *newz_ptr;
        STRLEN  len;

        Newz(0, newz_ptr, sizeof(struct sqlu_media_list), char);
        retval = newz_ptr;
        Newz(0, newz_ptr, sizeof(struct sqlu_media_entry), char);
        entries = newz_ptr;
        retval->media_type = SQLU_SERVER_LOCATION; /* Caller will override */
        retval->sessions = 1;
        retval->target.location = entries;

        val = SvPV(info_, len);
        if (len >= sizeof(entries->location_entry)) {
            croak("%s string '%s' too long - maximum %d bytes supported\n",
                  type_, val,
                  sizeof(entries->location_entry));
        }
        strcpy(entries->location_entry, val);
        /* warn("DEBUG: Value of %s is '%s'\n", type_, entries->location_entry); */
    } else {
        croak("Must specify array reference or string for %s", type_);
    }

    return retval;
}


MODULE = DB2::Admin    PACKAGE = DB2::Admin      PREFIX = DB2::Admin

PROTOTYPES: ENABLE

#
# Attach to a database instance
#
# Returns:
# - Success: attach info (string with 9 fields, separated by 0xff)
# - Failure: undef
#
# NOTE: we ignore the 'int' return value from sqleatin,
#       as IBM does not document it...
#
void
sqleatin(pNodeName, pUserName, pPassword)
     char* pNodeName
     char* pUserName
     char* pPassword
PPCODE:
     {
         SV *Return;

         sqleatin(pNodeName, pUserName, pPassword, &global_sqlca);
         if (global_sqlca.sqlcode == SQL_RC_OK) {
             Return = sv_newmortal();
             sv_setpv(Return, global_sqlca.sqlerrmc);
             XPUSHs(Return);
         } else {
             XSRETURN_UNDEF;
         }
     }


#
# Detach from a database instance
#
# Returns:
# - Success: 1
# - Failure: 0
#
# NOTE: we ignore the 'int' return value from sqleatin,
#       as IBM does not document it...
#
int
sqledtin()
CODE:
     sqledtin(&global_sqlca);
     if (global_sqlca.sqlcode == SQL_RC_OK) {
         RETVAL = 1;
     } else {
         RETVAL = 0;
     }
OUTPUT:
     RETVAL


#
# Connect to a database and stash the database handle
#
# Parameters:
# - Database alias (DSN format not supported)
# - Userid (may be empty)
# - Password (may be empty)
# - Connect Attributes (hash ref)
# Returns:
# - Boolean
#
void
db_connect(db_alias, userid, passwd, attrs)
    char *db_alias
    char *userid
    char *passwd
    SV   *attrs;

    PPCODE:
    {
        SQLRETURN   ret;
        SQLHANDLE   db_handle;
        int         error = 0;
        SV        **elem, *value;
        char       *key;
        I32         keylen;
#ifndef _WIN32                  /* Unix-specific */
        /* Check whether process id has changed */
        if (env_pid != 0 && env_pid != getpid()) {
            _do_cleanup_connections();
        }
#endif
        /* Allocate an environment handle on first call */
        if (env_handle == SQL_NULL_HENV) {
#ifndef _WIN32                  /* Unix-specific */
            env_pid = getpid();
#endif
            ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
                                 &env_handle);
            if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
                warn("Error allocating environment handle");
                env_handle = SQL_NULL_HENV;
                goto leave;
            }
        }

        /* Allocate the db_handles hash on first call */
        if (db_handles == NULL)
            db_handles = newHV();

        /*
         * Do we already have a connection to this database alias?
         * If so, warn and close the existing connection before
         * creating the new one.
         */
        elem = hv_fetch(db_handles, db_alias, strlen(db_alias), FALSE);
        if (elem) {
            char   *buf;
            STRLEN  len;

            warn("Connection to database '%s' already exists - will disconnect and re-connect", db_alias);
            /* We treat the handles as a string of bytes */
            buf = SvPV(*elem, len);
            if (len != sizeof(db_handle)) {
                croak("Oops - have buffer of size '%d', expected size '%d'",
                      len, sizeof(db_handle));
            }
            memcpy(&db_handle, buf, len);

            ret = SQLDisconnect(db_handle);
            if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
                warn("Failure disconnecting from '%s'", db_alias);
            }
            ret = SQLFreeHandle(SQL_HANDLE_DBC, db_handle);
            if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
                warn("Failure free-ing handle for '%s'", db_alias);
            }

            hv_delete(db_handles, db_alias, strlen(db_alias), G_DISCARD);

Admin.xs  view on Meta::CPAN

                                 &length) == SQL_SUCCESS) {
                message[length] = 0;
                if (message[length-1] == '\n')
                    message[length-1] = 0;
                warn("SQLConnect error %d: SQL code %d, SQL state '%s', message '%s'\n",
                     i, sqlcode, sqlstate, message);
                i++;
            }

            error = 1;
            SQLFreeHandle(SQL_HANDLE_DBC, db_handle);
            goto leave;
        }

        /*
         * Set AutoCommit (this is the default, but I like to
         * be explicit).
         */
        ret = SQLSetConnectAttr(db_handle,
                                SQL_ATTR_AUTOCOMMIT,
                                (SQLPOINTER)SQL_AUTOCOMMIT_ON,
                                SQL_NTS);
        if (ret != SQL_SUCCESS) {
            warn("Failure setting AutoCommit to 'on' for connection to database '%s'", db_alias);
            error = 1;
            SQLFreeHandle(SQL_HANDLE_DBC, db_handle);
            goto leave;
        }

        /*
         * Store new database handle - we treat it like
         * a string of bytes.
         */
        hv_store(db_handles, db_alias, strlen(db_alias),
                 newSVpv((char *)&db_handle, sizeof(db_handle)),
                 FALSE);

    leave:
        if (error == 0) {
            SV *Return;

            Return = sv_newmortal();
            sv_setiv(Return, 1);
            XPUSHs(Return);
        } else {
            XSRETURN_UNDEF;
        }
    }


#
# Disconnect from a database
#
# Returns:
# - Boolean
#
void
db_disconnect(db_alias)
     char *db_alias

    PPCODE:
    {
        SQLRETURN   ret;
        SQLHANDLE   db_handle;
        int         error = 0;
        SV        **elem;
#ifndef _WIN32                  /* Unix-specific */
        /* Check whether process id has changed */
        if (env_pid != 0 && env_pid != getpid()) {
            _do_cleanup_connections();
        }
#endif
        if (db_handles == 0) {
            warn("No database connections exist");
            error = 1;
            goto leave;
        }

        elem = hv_fetch(db_handles, db_alias, strlen(db_alias), FALSE);
        if (elem) {
            char   *buf;
            STRLEN  len;

            /* We treat the handles as a string of bytes */
            buf = SvPV(*elem, len);
            if (len != sizeof(db_handle)) {
                croak("Oops - have buffer of size '%d', expected size '%d'",
                      len, sizeof(db_handle));
            }
            memcpy(&db_handle, buf, len);

            ret = SQLDisconnect(db_handle);
            if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
                warn("Failure disconnecting from '%s'", db_alias);
                error = 1;
            }
            ret = SQLFreeHandle(SQL_HANDLE_DBC, db_handle);
            if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
                warn("Failure free-ing handle for '%s'", db_alias);
                error = 1;
            }
            hv_delete(db_handles, db_alias, strlen(db_alias), G_DISCARD);
        } else {
            warn("No connection to '%s' exists", db_alias);
            error = 1;
        }

    leave:
        if (error == 0) {
            SV *Return;

            Return = sv_newmortal();
            sv_setiv(Return, 1);
            XPUSHs(Return);
        } else {
            XSRETURN_UNDEF;
        }
    }


#
# Cleanup all handles at program end.  Invoked from END in perl module.
#
void
cleanup_connections()

     PPCODE:
     {
         _do_cleanup_connections();
     }


#
# Get/Set the monitor switches for this application
#
# Parameters:
# - Ref to hash with switch names and 0/1 value (missing: hold)
# - Version (SQLM_DBMON_VERSIONxxx)
# - Node (SQLM_CURRENT_NODE, SQLM_ALL_NODES, number)
# Returns:
# - Ref to sql element buffer with current switch state
#
void
db2MonitorSwitches(switches, version, node)
     SV *switches
     int version
     int node

     PPCODE:
     {
         db2MonitorSwitchesData      switchesData;
         struct sqlm_recording_group switchesList[SQLM_NUM_GROUPS];
         sqluint32                   outputFormat;
         char                       *key;
         I32                         keylen;
         SV                         *value;
         char                        output_buffer[SWITCHES_BUFFER_SIZE];

         if ((!SvROK(switches)) ||
             (SvTYPE(SvRV(switches)) != SVt_PVHV)) {
             croak("Hash reference expected for parameter 'switches'");
         }

         memset(&switchesData, 0, sizeof(switchesData));
         memset(&switchesList, 0, sizeof(switchesList));

         /*
          * Set the values of the sqlm_recording_group structure
          * - UnitOfWork
          * - Statement
          * - Table
          * - BufferPool
          * - Lock
          * - Sort
          * - Timestamp
          */
         switchesList[SQLM_UOW_SW].input_state = SQLM_HOLD;
         switchesList[SQLM_STATEMENT_SW].input_state = SQLM_HOLD;
         switchesList[SQLM_TABLE_SW].input_state = SQLM_HOLD;
         switchesList[SQLM_BUFFER_POOL_SW].input_state = SQLM_HOLD;
         switchesList[SQLM_LOCK_SW].input_state = SQLM_HOLD;
         switchesList[SQLM_SORT_SW].input_state = SQLM_HOLD;
#ifdef SQLM_TIMESTAMP_SW
         switchesList[SQLM_TIMESTAMP_SW].input_state = SQLM_HOLD;
#endif
         (void)hv_iterinit((HV*)SvRV(switches));
         while ((value = hv_iternextsv((HV*)SvRV(switches),
                                       (char **)&key, &keylen))) {
             int set = SvIV(value) ? SQLM_ON : SQLM_OFF;

             if (strEQ(key, "UnitOfWork")) {
                 switchesList[SQLM_UOW_SW].input_state = set;
             } else if (strEQ(key, "Statement")) {
                 switchesList[SQLM_STATEMENT_SW].input_state = set;
             } else if (strEQ(key, "Table")) {
                 switchesList[SQLM_TABLE_SW].input_state = set;
             } else if (strEQ(key, "BufferPool")) {
                 switchesList[SQLM_BUFFER_POOL_SW].input_state = set;
             } else if (strEQ(key, "Lock")) {
                 switchesList[SQLM_LOCK_SW].input_state = set;
             } else if (strEQ(key, "Sort")) {
                 switchesList[SQLM_SORT_SW].input_state = set;
#ifdef SQLM_TIMESTAMP_SW        /* New in DB2 V8 */
             } else if (strEQ(key, "Timestamp")) {
                 switchesList[SQLM_TIMESTAMP_SW].input_state = set;
#endif
             } else {
                 croak("Unexpected monitor switch '%s'\n", key);
             }
         }

         /* Set the values of the db2MonitorSwitchesData structure */
         memset(output_buffer, 0x00, SWITCHES_BUFFER_SIZE);
         switchesData.piGroupStates = switchesList;
         switchesData.poBuffer = output_buffer;
         switchesData.iVersion = version;
         switchesData.iBufferSize = SWITCHES_BUFFER_SIZE;
         switchesData.iReturnData = 1;
         switchesData.iNodeNumber = node;
         switchesData.poOutputFormat = &outputFormat;

         /* Call the db2MonitorSwitches API */
         db2MonitorSwitches(DB2_VERSION_ENUM, &switchesData, &global_sqlca);

         if (global_sqlca.sqlcode == SQL_RC_OK) {
             SV               *Return;
             sqlm_header_info *header;
             unsigned int      data_size;

             Return = sv_newmortal();
             header = (sqlm_header_info *)output_buffer;
             data_size = header->size + sizeof(sqlm_header_info);
             sv_setpvn(Return, output_buffer, data_size);
             XPUSHs(Return);
         } else {
             XSRETURN_UNDEF;
         }
     }


#
# Get the recommended buffer size for a snapshot
#
# Parameters:
# - Ref to array with classes/names, which will be converted to sqlma*
# - Version (SQLM_DBMON_VERSIONxxx)
# - Node (SQLM_CURRENT_NODE, SQLM_ALL_NODES, number)
# - Snapshot class (SQLM_CLASS_xxx)
# Returns:
# - Recommended snapshot size / undef on error
#
void
db2GetSnapshotSize(sqlma_data, version, node, class)
     struct sqlma * sqlma_data
     int version
     int node
     int class

     PPCODE:
     {
         sqluint32              size;
         db2GetSnapshotSizeData getSnapshotSizeParam;

         memset(&getSnapshotSizeParam, 0, sizeof(getSnapshotSizeParam));
         getSnapshotSizeParam.piSqlmaData = sqlma_data;
         getSnapshotSizeParam.poBufferSize = &size;
         getSnapshotSizeParam.iVersion = version;
         getSnapshotSizeParam.iNodeNumber = node;
#ifdef SQLM_CLASS_DEFAULT
         getSnapshotSizeParam.iSnapshotClass = class;
#else
         if (class != 0) {      /* SQLM_CLASS_DEFAULT */
             croak("Snapshot class not supported in this DB2 release");
         }
#endif
         db2GetSnapshotSize(DB2_VERSION_ENUM,
                            &getSnapshotSizeParam, &global_sqlca);
         Safefree(sqlma_data);
         if (global_sqlca.sqlcode == SQL_RC_OK) {
             SV  *Return;

             Return = sv_newmortal();
             sv_setuv(Return, size);
             XPUSHs(Return);
         } else {
             XSRETURN_UNDEF;
         }
     }


#
# Get a snapshot
#
# Parameters:
# - Ref to array with classes/names, which will be converted to sqlma*
# - Version (SQLM_DBMON_VERSIONxxx)
# - Node (SQLM_CURRENT_NODE, SQLM_ALL_NODES, number)
# - Snapshot class (SQLM_CLASS_xxx)
# - Initial output buffer size
# - Output buffer size increment
# - Store results in table
# Returns:
# - Buffer with snapshot results / undef
#
void
db2GetSnapshot(sqlma_data, version, node, class, buffer_size, buffer_increment, store_results)
     struct sqlma * sqlma_data
     int version
     int node
     int class
     int buffer_size
     int buffer_increment
     int store_results

     PPCODE:
     {
         db2GetSnapshotData getSnapshotParam;
         char              *output_buffer;
         db2Uint32          output_format;

         memset(&getSnapshotParam, 0, sizeof(getSnapshotParam));
         Newz(0, output_buffer, buffer_size, char);
         getSnapshotParam.piSqlmaData = sqlma_data;
         getSnapshotParam.poCollectedData = 0;
         getSnapshotParam.poBuffer = output_buffer;
         getSnapshotParam.iVersion = version;
         getSnapshotParam.iBufferSize = buffer_size;
         getSnapshotParam.iStoreResult = store_results;
         getSnapshotParam.iNodeNumber = node;
         getSnapshotParam.poOutputFormat = &output_format;
#ifdef SQLM_CLASS_DEFAULT
         getSnapshotParam.iSnapshotClass = class;
#else
         if (class != 0) {      /* SQLM_CLASS_DEFAULT */
             croak("Snapshot class not supported in this DB2 release");
         }
#endif

         db2GetSnapshot(DB2_VERSION_ENUM, &getSnapshotParam, &global_sqlca);

         while (global_sqlca.sqlcode == SQLM_RC_BUFFER_FULL) {
             Safefree(output_buffer);

             /* fprintf(stderr, "Buffer size for snapshot data is too small at %d bytes.\n", buffer_size); */
             /* fprintf(stderr, "Re-allocating memory for snapshot monitor data.\n"); */

             /* enlarge the buffer */
             buffer_size += buffer_increment;
             Newz(0, output_buffer, buffer_size, char);
             getSnapshotParam.poBuffer = output_buffer;
             getSnapshotParam.iBufferSize = buffer_size;
             /* fprintf(stderr, "Will call snapshot with increased buffer size %d\n", buffer_size); */
             db2GetSnapshot(DB2_VERSION_ENUM,
                            &getSnapshotParam, &global_sqlca);
         }
         Safefree(sqlma_data);

         if (global_sqlca.sqlcode == SQL_RC_OK ||
             global_sqlca.sqlcode == SQLM_RC_NO_DATA) {
             SV               *Return;
             sqlm_header_info *header;
             int               data_size;

             Return = sv_newmortal();
             if (global_sqlca.sqlcode == SQL_RC_OK) {
                 header = (sqlm_header_info *)output_buffer;
                 data_size = header->size + sizeof(sqlm_header_info);
                 sv_setpvn(Return, output_buffer, data_size);
             } else {
                 sv_setpvn(Return, "", 0);
             }
             Safefree(output_buffer);
             XPUSHs(Return);
         } else {
             Safefree(output_buffer);

Admin.xs  view on Meta::CPAN

     char *db_alias
     int   version
     int   node

     CODE:
     {
         db2ResetMonitorData resetMonitorParam;

         memset(&resetMonitorParam, 0, sizeof(resetMonitorParam));
         resetMonitorParam.iResetAll = reset_all;
         resetMonitorParam.iVersion = version;
         resetMonitorParam.iNodeNumber = node;
         if (strlen(db_alias)) {
             if (strlen(db_alias) > SQL_ALIAS_SZ) {
                 croak("Database alias '%s' too long (max %d bytes)",
                       db_alias, SQL_ALIAS_SZ);
             }
             resetMonitorParam.piDbAlias = db_alias;
         } else {
             resetMonitorParam.piDbAlias = NULL;
         }
         db2ResetMonitor(DB2_VERSION_ENUM, &resetMonitorParam, &global_sqlca);
         RETVAL = (global_sqlca.sqlcode == SQL_RC_OK ? 1 : 0);
     }
OUTPUT:
     RETVAL

#
# Get / set database manager / database configuration
# is available starting with DB2 release V8.1
#

#
# Get database manager / database configuration parameters
#
# Parameters:
# - Ref to array of parameters, each a hash reference
#   with the following keys:
#   - Token (numeric)
#   - Size (numeric; determined at the perl level from a lookup table)
# - Flags: Ref to hash with 'Database' / 'Manager' and
#          'Immediate' / 'Delayed' / 'GetDefaults' (treated like a bitmap,
#          and checked at the caller level, not here)
# - Database name (may be NULL)
# - Version (SQLM_DBMON_VERSIONxxx)
# Returns:
# - Ref to array of return values, each a hash reference
#   with the following keys:
#   - Token
#   - Value
#   - Automatic (optional)
#   - Computed (optional, V9.1 only)
#
void
db2CfgGet(params, flags, dbname, version)
     SV   *params
     SV   *flags
     char *dbname
     int   version

     PPCODE:
     {
         char        *buffer, *buffer_ptr, *key;
         size_t       buffer_size;
         int          array_length, counter, *sizes, error = 0;
         AV          *params_array;
         HV          *flags_hash;
         I32          keylen;
         SV          *value;
         db2CfgParam *cfgParam;
         db2Cfg       cfgStruct;

         /*
          * Verify we have an array, then iterate over it to
          * determine a proper buffer size.  While we do this,
          * we build up the 'token' and 'flags' parts of the
          * parameter structure.
          */
         if (!SvROK(params))
             croak("Reference expected for parameter 'params'");
         if (SvTYPE(SvRV(params)) != SVt_PVAV)
             croak("Array reference expected for parameter 'params'");
         params_array = (AV*)SvRV(params);
         array_length = av_len(params_array) + 1; /* Num elements */

         buffer_size = 0;
         Newz(0, sizes, array_length, int);
         Newz(0, cfgParam, array_length, db2CfgParam);
         for (counter = 0; counter < array_length; counter++) {
             SV **array_elem;
             HV  *entry;
             int  have_size = 0, have_token = 0;

             array_elem = av_fetch(params_array, counter, FALSE);
             if (!SvROK(*array_elem))
                 croak("Reference expected for 'params' element %d", counter);
             if (SvTYPE(SvRV(*array_elem)) != SVt_PVHV)
                 croak("Hash reference expected for 'params' element %d",
                       counter);
             entry = (HV*)SvRV(*array_elem);

             /*
              * Iterate over all hash key/value pairs, so we can
              * check if anything unknown is specified.
              */
             while ((value = hv_iternextsv(entry, (char **)&key, &keylen))) {
                 if (strEQ(key, "Token")) {
                     have_token = 1;
                     if ((!SvROK(value)) && looks_like_number(value)) {
                         int token_val = SvIV(value);
                         cfgParam[counter].token = token_val;
                     } else {
                         croak("Invalid data in params elem %d, key %s: not an integer", counter, key);
                     }
                 } else if (strEQ(key, "Size")) {
                     have_size = 1;
                     if ((!SvROK(value)) && looks_like_number(value)) {
                         int elem_size = SvIV(value);
                         int padded_size = (elem_size + 3) & ~3;
                         sizes[counter] = elem_size;
                         buffer_size += padded_size;

Admin.xs  view on Meta::CPAN

                 /* Find first occurrence of 'AA', as that indicates the actual size of the element written */
                 first = memchr(cfgParam[counter].ptrvalue, 0xaa,  1024);
                 if (first) {
                     int actual_size = first - cfgParam[counter].ptrvalue;
                     //warn("Have actual size '%d'", actual_size);
                     if (actual_size > elem_size) {
                         warn("For token %d, have supposed size %d and actual size %d\n", cfgParam[counter].token, elem_size, actual_size);
                     }
                 }
#endif

                 if ((cfgParam[counter].flags & db2CfgParamAutomatic) ==
                     db2CfgParamAutomatic) {
                     hv_store(elem, "Automatic", 9, newSViv(1), FALSE);
                 }
#ifdef db2CfgParamComputed
                 if ((cfgParam[counter].flags & db2CfgParamComputed) ==
                     db2CfgParamComputed) {
                     hv_store(elem, "Computed", 8, newSViv(1), FALSE);
                 }
#endif
                 av_push(retval, newRV_noinc((SV*)elem));
             }
             Return = newRV_noinc((SV*)retval);
             XPUSHs(Return);
         } else {   /* error = 1, or sqlcoe != OK */
             XSRETURN_UNDEF;
         }
         Safefree(cfgParam);
         Safefree(buffer);
         Safefree(sizes);
     }


#
# Set database manager / database configuration parameters
#
# Parameters:
# - Ref to array of parameters, each a hash reference
#   with the following keys:
#   - Token (numeric)
#   - Value
#   - Automatic (optional)
#   - Computed (optional, V9.1)
#   - Manual (optional, V9.1)
# - Flags: Ref to hash with 'Database' / 'Manager' and
#          'Immediate' / 'Delayed' / 'Reset' (treated like a bitmap,
#          and checked at the caller level, not here)
# - Database name (may be NULL)
# - Version (SQLM_DBMON_VERSIONxxx)
# Returns:
# - 1 on success, undef on failure
#
void
db2CfgSet(params, flags, dbname, version)
     SV   *params
     SV   *flags
     char *dbname
     int   version

     PPCODE:
     {
         char        *key;
         int          array_length, counter, error = 0;
         AV          *params_array;
         HV          *flags_hash;
         I32          keylen;
         SV          *value;
         db2CfgParam *cfgParam;
         db2Cfg       cfgStruct;

         /*
          * Verify we have an array, then iterate over it to
          * build the cfgParam parameter structure.
          */
         if (!SvROK(params))
             croak("Reference expected for parameter 'params'");
         if (SvTYPE(SvRV(params)) != SVt_PVAV)
             croak("Array reference expected for parameter 'params'");
         params_array = (AV*)SvRV(params);
         array_length = av_len(params_array) + 1; /* Num elements */

         /* Set the main db2Cfg structure */
         Newz(0, cfgParam, array_length, db2CfgParam);
         memset(&cfgStruct, 0, sizeof(cfgStruct));
         cfgStruct.numItems = array_length;
         cfgStruct.paramArray = cfgParam;

         /*
          * Process flags hash to build bitfield.
          * We need to do this before we process the
          * list of config parameters, as thatv needs to know whether
          * the 'Reset' flag is set.
          */
         if (!SvROK(flags))
             croak("Reference expected for parameter 'flags'");
         if (SvTYPE(SvRV(flags)) != SVt_PVHV)
             croak("Hash reference expected for parameter 'flags'");
         flags_hash = (HV*)SvRV(flags);

         /*
          * Iterate over all hash key/value pairs, so we can
          * check if anything unknown is specified.
          */
         while ((value = hv_iternextsv(flags_hash, (char **)&key, &keylen))) {
             int cur_flag = 0;

             if (strEQ(key, "Database")) {
                 cur_flag = db2CfgDatabase;
             } else if (strEQ(key, "Manager")) {
                 cur_flag = db2CfgDatabaseManager;
             } else if (strEQ(key, "Immediate")) {
                 cur_flag = db2CfgImmediate;
             } else if (strEQ(key, "Delayed")) {
                 cur_flag = db2CfgDelayed;
             } else if (strEQ(key, "Reset")) {
                 cur_flag = db2CfgReset;
             } else {
                 croak("Invalid 'flags' key '%s'\n", key);
             }

Admin.xs  view on Meta::CPAN

                 } else if (strEQ(key, "Automatic")) {
                     if (SvTRUE(value)) {
                         cfgParam[counter].flags |= db2CfgParamAutomatic;
                     }
#ifdef db2CfgParamComputed
                 } else if (strEQ(key, "Computed")) {
                     if (SvTRUE(value)) {
                         cfgParam[counter].flags |= db2CfgParamComputed;
                     }
#endif
#ifdef db2CfgParamManual
                 } else if (strEQ(key, "Manual")) {
                     if (SvTRUE(value)) {
                         cfgParam[counter].flags |= db2CfgParamManual;
                     }
#endif
                 } else {
                     croak("Invalid data in params elem %d: Unexpected key %s",
                           counter, key);
                 }
             } /* End while: hash iteration */
             if (have_token == 0) {
                 croak("Invalid data in params elem %d: Required element 'Token' missing",  counter);
             }
             if (have_value == 0 && (cfgStruct.flags & db2CfgReset) != db2CfgReset) {
                 croak("Invalid data in params elem %d: Required element 'Value' missing",  counter);
             } else if (have_value && (cfgStruct.flags & db2CfgReset) == db2CfgReset) {
                 croak("Invalid data in params elem %d: element 'Value' not allowed with flag 'Reset'");
             }
         } /* End for: each array element*/

         /* Make the call and return */
         if (error == 0)
         db2CfgSet(version, (void *)&cfgStruct, &global_sqlca);
         Safefree(cfgParam);
         if (error == 0 && global_sqlca.sqlcode == SQL_RC_OK) {
             SV  *Return;

             Return = sv_newmortal();
             sv_setiv(Return, 1);
             XPUSHs(Return);
         } else {  /* Error, or SQl code != OK */
             XSRETURN_UNDEF;
         }
     }


#
# Inquire the database directory.
#
# Parameters:
# - Path name (optional: empty string will query system database directory)
# Returns:
# - Ref to array of hash-references with fields like 'DBName',
#   'Alias', 'Path' or undef on failure
#
void
db2DatabaseDirectory(path)
     char *path

     PPCODE:
     {
         unsigned short  num_entries;
         SV             *Return;
         AV             *retval;
         int             counter, error = 0;
#ifdef ADMIN_API_HAVE_DB2DBDIR_V8
         struct          db2DbDirOpenScanStruct    open_param;
         struct          db2DbDirNextEntryStruct   next_entry_param;
         struct          db2DbDirCloseScanStruct   close_param;
#elif ADMIN_API_HAVE_DB2DBDIR_V9
         struct          db2DbDirOpenScanStruct    open_param;
         struct          db2DbDirNextEntryStructV9 next_entry_param;
         struct          db2DbDirCloseScanStruct   close_param;
#else
#error Either DB2DIR V8 or V9 must be set
#endif

         if (path && *path == 0x00) {
             path = NULL;
         }
         open_param.piPath = path;
         db2DbDirOpenScan(DB2_VERSION_ENUM, &open_param, &global_sqlca);
         if (global_sqlca.sqlcode == SQL_RC_OK) {
             next_entry_param.iHandle = close_param.iHandle =
                 open_param.oHandle;
             num_entries = open_param.oNumEntries;
         } else {
             warn("db2DatabaseDirectory: db2DbDirOpenScan() failed with sqlcode %d",
                  global_sqlca.sqlcode);
             error = 1;
             goto leave;
         }

         /*
          * NOTE: The keys returned match the db2CatalogDatabase
          *       parameters.  Keep them in sync.
          */
         retval = (AV*)sv_2mortal((SV*)newAV());
         for (counter = 0; counter < num_entries; counter++) {
             HV                    *entry;
             unsigned int           len;
             char                  *ptr;
#ifdef ADMIN_API_HAVE_DB2DBDIR_V8
             struct db2DbDirInfo   *dir_entry;
#elif ADMIN_API_HAVE_DB2DBDIR_V9
             struct db2DbDirInfoV9 *dir_entry;
#else
#error Either DB2DIR V8 or V9 must be set
#endif
#ifdef ADMIN_API_HAVE_DB2DBDIR_V8
             db2DbDirGetNextEntry(DB2_VERSION_ENUM,
                                  &next_entry_param, &global_sqlca);
             if (global_sqlca.sqlcode == SQL_RC_OK) {
                 dir_entry = next_entry_param.poDbDirEntry;
             } else {
                 warn("db2DatabaseDirectory: db2DirGetNextEntry() (V8.2) failed with sqlcode %d",
                      global_sqlca.sqlcode);
                 error = 1;
                 goto leave;
             }

Admin.xs  view on Meta::CPAN

                 ptr = "Unknown authentication type";
             }
             hv_store(entry, "Authentication", 14, newSVpvn(ptr, strlen(ptr)), FALSE);

             len = padstrlen(dir_entry->glbdbname, sizeof(dir_entry->glbdbname));
             if (len && dir_entry->type == SQL_DCE) {
                 hv_store(entry, "DCE Global Name", 14, newSVpvn(dir_entry->glbdbname, len), FALSE);
             }
             len = padstrlen(dir_entry->dceprincipal, sizeof(dir_entry->dceprincipal));
             if (len) {
                 hv_store(entry, "Principal", 9, newSVpvn(dir_entry->dceprincipal, len), FALSE);
             }
             /* DB2 'list database directory' does not suppress -1 here */
             hv_store(entry, "Catalog Node Number", 19, newSViv(dir_entry->cat_nodenum), FALSE);
             if (dir_entry->nodenum != -1) {
                 hv_store(entry, "Node Number", 11, newSViv(dir_entry->nodenum), FALSE);
             }
             len = padstrlen(dir_entry->althostname, sizeof(dir_entry->althostname));
             if (len) {
                 hv_store(entry, "Alternate HostName", 18,
                          newSVpvn(dir_entry->althostname, len), FALSE);
             }
             len = padstrlen(dir_entry->altportnumber, sizeof(dir_entry->altportnumber));
             if (len) {
                 hv_store(entry, "Alternate Port Number", 21,
                          newSVpvn(dir_entry->altportnumber, len), FALSE);
             }
             /* Add hash to result */
             av_push(retval, newRV_noinc((SV*)entry));
         }
         db2DbDirCloseScan(DB2_VERSION_ENUM, &close_param, &global_sqlca);
         if (global_sqlca.sqlcode != SQL_RC_OK) {
             warn("db2DatabaseDirectory: db2DbDirCloseScan() failed with sqlcode %d",
                  global_sqlca.sqlcode);
             /* Fall-through - we have results */
         }

         Return = newRV_noinc((SV*)retval);
         XPUSHs(Return);

     leave:
         /* FIXME: should clear up retval array if defined */
         if (error) {
             XSRETURN_UNDEF;
         }
     }


#
# Catalog a database
#
# Parameters:
# - Reference to a hash with relevant fields
# Returns:
# - Boolean
#
void
sqlecadb(params)
    SV *params

    PPCODE:
    {
        char           *dbname = NULL, *db_alias = NULL, *node_name = NULL;
        char           *path = NULL, *comment = NULL, *principal = NULL;
        unsigned char   db_type = 0x00;
        unsigned short  auth = SQL_AUTHENTICATION_NOT_SPEC;
        char           *key;
        I32             keylen;
        SV             *value;

        if ((!SvROK(params)) ||
             (SvTYPE(SvRV(params)) != SVt_PVHV)) {
             croak("Hash reference expected for parameter 'params'");
         }

        /*
         * Iterate over the hash and extract keys matching
         * GetDatabaseDirectory:
         * - Alias
         * - Database
         * - NodeName
         * - Path
         * - Comment
         * - DBType
         * - Authentication
         * - Principal
         */
         (void)hv_iterinit((HV*)SvRV(params));
         while ((value = hv_iternextsv((HV*)SvRV(params),
                                       (char **)&key, &keylen))) {
             if (SvPOK(value)) {
                 char   *val;
                 STRLEN  len;

                 val = SvPV(value, len);

                 if (strEQ(key, "Alias")) {
                     db_alias = val;
                 } else if (strEQ(key, "Database")) {
                     dbname = val;
                 } else if (strEQ(key, "NodeName")) {
                     node_name = val;
                 } else if (strEQ(key, "Path")) {
                     path = val;
                 } else if (strEQ(key, "Comment")) {
                     if (len > 30) { /* No constant in header file? */
                         croak("Comment too long - have '%d' characters, maximum is '%d'\n", len, 30);
                     }
                     comment = val;
                 } else if (strEQ(key, "DBType")) {
                     if (strcmp(val, "Indirect") == 0) {
                         db_type = SQL_INDIRECT;
                     } else if (strcmp(val, "Remote") == 0) {
                         db_type = SQL_REMOTE;
                     } else if (strcmp(val, "DCE") == 0) {
                         db_type = SQL_DCE;
                     } else {
                         croak("Unexpected DBType value '%s'\n", val);
                     }
                 } else if (strEQ(key, "Authentication")) {
                     if (strcmp(val, "Server") == 0) {

Admin.xs  view on Meta::CPAN

                         auth = SQL_AUTHENTICATION_DATAENC;
                     } else if (strcmp(val, "GSS Plugin") == 0) {
                         auth = SQL_AUTHENTICATION_GSSPLUGIN;
                     } else if (strcmp(val, "GSS Plugin / Server Encrypt") == 0) {
                         /* Missing from V8.2 manual */
                         auth = SQL_AUTHENTICATION_GSS_SVR_ENC;
                     } else if (strcmp(val, "Server / Optional Data Encrypted") == 0) {
                         /* Missing from V8.2 manual */
                         auth = SQL_AUTHENTICATION_DATAENC_CMP;
#endif
                     } else {
                         croak("Unexpected Authentication value '%s'\n", val);
                     }
                 } else if (strEQ(key, "Principal")) {
                     principal = val;
                 } else {
                     croak("Unexpected database catalog entry '%s'\n", key);
                 }
             } else {
                 croak("Database catalog entry '%s' is not a string\n", key);
             }
         } /* End while: all keys */

         /* Check that the required entries are present */
         if (db_alias == NULL)
             croak("Required parameter 'Alias' is missing\n");
         if (dbname == NULL)
             croak("Required parameter 'Database' is missing\n");
         if (db_type == 0x00)
             croak("Required parameter 'DBType' is missing\n");

         /* Make the call and return the result */
         sqlecadb(dbname, db_alias, db_type, node_name, path,
                  comment, auth, principal, &global_sqlca);
         if (global_sqlca.sqlcode != SQL_RC_OK) {
             warn("Call to sqlecadb() failed with sqlcode %d",
                  global_sqlca.sqlcode);
             XSRETURN_UNDEF;
         } else {
             SV *Return;

             Return = sv_newmortal();
             sv_setiv(Return, 1);
             XPUSHs(Return);
         }
     }


#
# Uncatalog a database
#
# Parameters:
# - Database alias
# Returns:
# - Boolean
#
void
sqleuncd(db_alias)
    char *db_alias

    PPCODE:
    {
         sqleuncd(db_alias, &global_sqlca);
         if (global_sqlca.sqlcode != SQL_RC_OK) {
             warn("Call to sqleuncd() failed with sqlcode %d",
                  global_sqlca.sqlcode);
             XSRETURN_UNDEF;
         } else {
             SV *Return;

             Return = sv_newmortal();
             sv_setiv(Return, 1);
             XPUSHs(Return);
         }
     }


#
# Inquire the node directory
#
# Parameters: none
# Returns:
# - Ref to array of hash-references with fields like 'DBName',
#   'Alias', 'Path' or undef on failure
#
void
db2NodeDirectory()

     PPCODE:
     {
         unsigned short  dir_handle, num_entries;
         SV             *Return;
         AV             *retval;
         int             counter, error = 0;

         sqlenops(&dir_handle, &num_entries, &global_sqlca);
         if (global_sqlca.sqlcode != SQL_RC_OK) {
             if (global_sqlca.sqlcode != SQLE_RC_NONODEDIR) {
                 warn("db2NodeDirectory: sqlenops() failed with sqlcode %d",
                      global_sqlca.sqlcode);
                 error = 1;
             }
             goto leave;
         }

         retval = (AV*)sv_2mortal((SV*)newAV());
         for (counter = 0; counter < num_entries; counter++) {
             HV               *entry;
             struct sqleninfo *dir_entry;
             unsigned int      len;
             char             *ptr;

             sqlengne(dir_handle, &dir_entry, &global_sqlca);
             if (global_sqlca.sqlcode != SQL_RC_OK) {
                 warn("db2NodeDirectory: sqlengne() failed with sqlcode %d",
                      global_sqlca.sqlcode);
                 error = 1;
                 goto leave;
             }

             entry = newHV();
             len = padstrlen(dir_entry->nodename, sizeof(dir_entry->nodename));
             if (len) {
                 hv_store(entry, "NodeName", 8, newSVpvn(dir_entry->nodename, len), FALSE);
             }
             len = padstrlen(dir_entry->local_lu, sizeof(dir_entry->local_lu));
             if (len) {
                 hv_store(entry, "Local LU", 9, newSVpvn(dir_entry->local_lu, len), FALSE);
             }
             len = padstrlen(dir_entry->partner_lu, sizeof(dir_entry->partner_lu));
             if (len) {
                 hv_store(entry, "Partner LU", 9, newSVpvn(dir_entry->partner_lu, len), FALSE);
             }
             len = padstrlen(dir_entry->mode, sizeof(dir_entry->mode));
             if (len) {
                 hv_store(entry, "Mode", 4, newSVpvn(dir_entry->mode, len), FALSE);
             }
             len = padstrlen(dir_entry->comment, sizeof(dir_entry->comment));
             if (len) {
                 hv_store(entry, "Comment", 7, newSVpvn(dir_entry->comment, len), FALSE);
             }
             if (dir_entry->protocol == SQL_PROTOCOL_NETB) {
                 hv_store(entry, "Adapter", 7, newSViv(dir_entry->adapter), FALSE);
             }
             len = padstrlen(dir_entry->networkid, sizeof(dir_entry->networkid));
             if (len) {
                 hv_store(entry, "Network ID", 10, newSVpvn(dir_entry->networkid, len), FALSE);
             }

Admin.xs  view on Meta::CPAN

             len = padstrlen(dir_entry->system_name, sizeof(dir_entry->system_name));
             if (len) {
                 hv_store(entry, "SystemName", 11,
                          newSVpvn(dir_entry->system_name, len), FALSE);
             }
             len = padstrlen(dir_entry->remote_instname, sizeof(dir_entry->remote_instname));
             if (len) {
                 hv_store(entry, "RemoteInstName", 14,
                          newSVpvn(dir_entry->remote_instname, len), FALSE);
             }

             /* Catalog node type: 0=normal, 2: admin */
             switch(dir_entry->catalog_node_type) {
             case 0:
                 ptr = "Normal"; break;
             case 2:
                 ptr = "Admin"; break;
             default:
                 ptr = "unknown catalog node type";
             }
             hv_store(entry, "CatalogNodeType", 15,
                      newSVpvn(ptr, strlen(ptr)), FALSE);

             /* OS type must be decoded by caller */
             hv_store(entry, "OSType", 6, newSViv(dir_entry->os_type), FALSE);

             /* Add hash to result */
             av_push(retval, newRV_noinc((SV*)entry));
         }

         sqlencls(dir_handle, &global_sqlca);
         if (global_sqlca.sqlcode != SQL_RC_OK) {
             warn("db2NodeDirectory: sqlencls() failed with sqlcode %d",
                  global_sqlca.sqlcode);
             /* Fall-through - we have results */
         }

         Return = newRV_noinc((SV*)retval);
         XPUSHs(Return);

     leave:
         /* FIXME: should clear up retval array if defined */
         if (error) {
             XSRETURN_UNDEF;
         }
     }


#
# Catalog a node
#
# Parameters:
# - Reference to a hash with relevant fields
# Returns:
# - Boolean
#
void
sqlectnd(params)
    SV *params

    PPCODE:
    {
        char                     protocol;
        struct sqle_node_struct  generic_node_info = { SQL_NODE_STR_ID, 0, "", "", 0 };
        struct sqle_node_tcpip   tcpip_node_info = { "", "" };
        struct sqle_node_local   local_node_info = { "" };
        void                    *protocol_info;
        char                    *key;
        I32                      keylen;
        SV                      *value, **elem;

        if ((!SvROK(params)) ||
            (SvTYPE(SvRV(params)) != SVt_PVHV)) {
            croak("Hash reference expected for parameter 'params'");
        }

        /* Get the 'protocol' parameter before doing anything else */
        elem = hv_fetch((HV*)SvRV(params), "Protocol", 8, FALSE);
        if (elem == NULL)
            croak("Required parameter 'Protocol' missing\n");
        if (SvPOK(*elem)) {
            char   *val;
            STRLEN  len;

            val = SvPV(*elem, len);
            if (strcmp(val, "TCPIP") == 0 ||
                strcmp(val, "TCP/IP") == 0) {
                protocol = SQL_PROTOCOL_TCPIP;
                protocol_info = &tcpip_node_info;
#ifdef SQL_PROTOCOL_TCPIP4
            } else if (strcmp(val, "TCPIP4") == 0 ||
                       strcmp(val, "TCP/IPv4") == 0) {
                protocol = SQL_PROTOCOL_TCPIP4;
                protocol_info = &tcpip_node_info;
#endif
#ifdef SQL_PROTOCOL_TCPIP6
            } else if (strcmp(val, "TCPIP6") == 0 ||
                       strcmp(val, "TCP/IPv6") == 0) {
                protocol = SQL_PROTOCOL_TCPIP6;
                protocol_info = &tcpip_node_info;
#endif
            } else if (strcmp(val, "SOCKS") == 0 ||
                       strcmp(val, "TCP/IP using SOCKS") == 0) {
                protocol = SQL_PROTOCOL_SOCKS;
                protocol_info = &tcpip_node_info;
#ifdef SQL_PROTOCOL_SOCKS4
            } else if (strcmp(val, "SOCKS4") == 0 ||
                       strcmp(val, "TCP/IPv4 using SOCKS") == 0) {
                protocol = SQL_PROTOCOL_SOCKS4;
                protocol_info = &tcpip_node_info;
#endif
            } else if (strcmp(val, "Local") == 0 ||
                       strcmp(val, "Local IPC") == 0) {
                protocol = SQL_PROTOCOL_LOCAL;
                protocol_info = &local_node_info;
            } else {
                croak("Unexpected protocol value '%s'\n", val);
            }
        } else
            croak("Protocol value is not a string");

Admin.xs  view on Meta::CPAN

                             sizeof(local_node_info.instance_name));
                 } else {
                     croak("Unexpected node directory field '%s'\n", key);
                 }
             } else {
                 croak("Node directory field '%s' is not a string\n", key);
             }
         } /* End while: all keys */

         /* Check that the required entries are present */
         if (! generic_node_info.nodename[0])
             croak("Required parameter 'NodeName' is missing\n");
         if (protocol == SQL_PROTOCOL_TCPIP ||
#ifdef SQL_PROTOCOL_TCPIP4
             protocol == SQL_PROTOCOL_TCPIP4 ||
#endif
#ifdef SQL_PROTOCOL_TCPIP6
             protocol == SQL_PROTOCOL_TCPIP6 ||
#endif
#ifdef SQL_PROTOCOL_SOCKS4
             protocol == SQL_PROTOCOL_SOCKS4 ||
#endif
             protocol == SQL_PROTOCOL_SOCKS) {
             if (! tcpip_node_info.hostname[0])
                 croak("Required parameter 'HostName' is missing\n");
             if (! tcpip_node_info.service_name[0])
                 croak("Required parameter 'ServiceName' is missing\n");
         }
         if (protocol == SQL_PROTOCOL_LOCAL &&
             ! local_node_info.instance_name[0])
             croak("Required parameter 'InstanceName' is missing\n");

         /* Make the call and return the result */
         sqlectnd(&generic_node_info, protocol_info, &global_sqlca);
         if (global_sqlca.sqlcode != SQL_RC_OK) {
             warn("Call to sqlectnd() failed with sqlcode %d",
                  global_sqlca.sqlcode);
             XSRETURN_UNDEF;
         } else {
             SV *Return;

             Return = sv_newmortal();
             sv_setiv(Return, 1);
             XPUSHs(Return);
         }
     }


#
# Uncatalog a node
#
# Parameters:
# - Node name
# Returns:
# - Boolean
#
void
sqleuncn(node_name)
    char *node_name

    PPCODE:
    {
         sqleuncn(node_name, &global_sqlca);
         if (global_sqlca.sqlcode != SQL_RC_OK) {
             warn("Call to sqleuncn() failed with sqlcode %d",
                  global_sqlca.sqlcode);
             XSRETURN_UNDEF;
         } else {
             SV *Return;

             Return = sv_newmortal();
             sv_setiv(Return, 1);
             XPUSHs(Return);
         }
     }


#
# Inquire the DCS (gateway) directory
#
# Parameters: none
# Returns:
# - Ref to array of hash-references with fields like 'DBName',
#   'Alias', 'Path' or undef on failure
#
void
db2DCSDirectory()

     PPCODE:
     {
         short  num_entries;
         SV    *Return;
         AV    *retval;
         int    error = 0;

         sqlegdsc(&num_entries, &global_sqlca);
         if (global_sqlca.sqlcode != SQL_RC_OK) {
             if (global_sqlca.sqlcode != SQLE_RC_NO_ENTRY &&
                 global_sqlca.sqlcode != SQLE_RC_LDB_NF) {
                 warn("db2DCSDirectory: sqlegdsc() failed with sqlcode %d",
                      global_sqlca.sqlcode);
                 error = 1;
             }
             goto leave;
         }

         retval = (AV*)sv_2mortal((SV*)newAV());
         if (num_entries > 0) {
             struct sql_dir_entry *buffer;
             short                 actual_num_entries;
             int                   counter;

             Newz(0, buffer, num_entries, struct sql_dir_entry);
             actual_num_entries = num_entries;
             sqlegdgt(&actual_num_entries, buffer, &global_sqlca);
             if (global_sqlca.sqlcode != SQL_RC_OK) {
                 if (global_sqlca.sqlcode != SQLE_RC_NO_ENTRY) {
                     warn("db2DCSDirectory: sqlegdgt() failed with sqlcode %d",
                          global_sqlca.sqlcode);
                     error = 1;
                 }
                 goto leave;
             }

             for (counter = 0; counter < actual_num_entries; counter++) {
                 struct sql_dir_entry *dir_entry;
                 HV                   *entry;
                 int                   len;

                 entry = newHV();
                 dir_entry = buffer + counter;

                 hv_store(entry, "DirLevel", 8, newSViv(dir_entry->release), FALSE);
                 len = padstrlen(dir_entry->comment, sizeof(dir_entry->comment));
                 if (len) {
                     hv_store(entry, "Comment", 7, newSVpvn(dir_entry->comment, len), FALSE);
                 }
                 len = padstrlen(dir_entry->ldb, sizeof(dir_entry->ldb));
                 if (len) {
                     hv_store(entry, "Database", 8, newSVpvn(dir_entry->ldb, len), FALSE);
                 }
                 len = padstrlen(dir_entry->tdb, sizeof(dir_entry->tdb));
                 if (len) {
                     hv_store(entry, "Target", 6, newSVpvn(dir_entry->tdb, len), FALSE);
                 }
                 len = padstrlen(dir_entry->ar, sizeof(dir_entry->ar));
                 if (len) {
                     hv_store(entry, "Library", 7, newSVpvn(dir_entry->ar, len), FALSE);
                 }
                 len = padstrlen(dir_entry->parm, sizeof(dir_entry->parm));
                 if (len) {
                     hv_store(entry, "Parameter", 9, newSVpvn(dir_entry->parm, len), FALSE);
                 }

                 /* Add hash to result */
                 av_push(retval, newRV_noinc((SV*)entry));
             } /* End foreach: entry */
             Safefree(buffer);
         } /* End if: have DCS catalog entries */

         sqlegdcl(&global_sqlca);
         if (global_sqlca.sqlcode != SQL_RC_OK) {
             warn("db2DCSDirectory: sqlegdcl() failed with sqlcode %d",
                  global_sqlca.sqlcode);
             /* Fall-through - we have results */
         }

         Return = newRV_noinc((SV*)retval);
         XPUSHs(Return);

     leave:
         if (error) {
             XSRETURN_UNDEF;
         }
     }


#
# Catalog a DCS database
#
# Parameters:
# - Reference to a hash with relevant fields
# Returns:
# - Boolean
#
void
sqlegdad(params)
    SV *params

    PPCODE:
    {
        struct sql_dir_entry  dcs_node_info = { SQL_DCS_STR_ID, 0, 0, "", "", "", "", "" };
        char                 *key;
        I32                   keylen;
        SV                   *value;

        if ((!SvROK(params)) ||
            (SvTYPE(SvRV(params)) != SVt_PVHV)) {
            croak("Hash reference expected for parameter 'params'");
        }

        /*
         * Iterate over the hash and extract keys matching:
         * - Database
         * - Target
         * - Comment
         * - Library
         * - Parameter
         */
         (void)hv_iterinit((HV*)SvRV(params));
         while ((value = hv_iternextsv((HV*)SvRV(params),
                                       (char **)&key, &keylen))) {
             if (SvPOK(value)) {
                 char   *val;
                 STRLEN  len;

                 val = SvPV(value, len);

                 if (strEQ(key, "Database")) {
                     if (len > sizeof(dcs_node_info.ldb))
                         croak("Value specified for '%s' is too long - maximum length is %d characters", key, sizeof(dcs_node_info.ldb));
                     strncpy(dcs_node_info.ldb, val,
                             sizeof(dcs_node_info.ldb));
                 } else if (strEQ(key, "Target")) {
                     if (len > sizeof(dcs_node_info.tdb))
                         croak("Value specified for '%s' is too long - maximum length is %d characters", key, sizeof(dcs_node_info.tdb));
                     strncpy(dcs_node_info.tdb, val,
                             sizeof(dcs_node_info.tdb));
                 } else if (strEQ(key, "Comment")) {
                     if (len > sizeof(dcs_node_info.comment))
                         croak("Value specified for '%s' is too long - maximum length is %d characters", key, sizeof(dcs_node_info.comment));
                     strncpy(dcs_node_info.comment, val,
                             sizeof(dcs_node_info.comment));
                 } else if (strEQ(key, "Library")) {
                     if (len > sizeof(dcs_node_info.ar))
                         croak("Value specified for '%s' is too long - maximum length is %d characters", key, sizeof(dcs_node_info.ar));
                     strncpy(dcs_node_info.ar, val,
                             sizeof(dcs_node_info.ar));
                 } else if (strEQ(key, "Parameter")) {
                     if (len > sizeof(dcs_node_info.parm))
                         croak("Value specified for '%s' is too long - maximum length is %d characters", key, sizeof(dcs_node_info.parm));
                     strncpy(dcs_node_info.parm, val,
                             sizeof(dcs_node_info.parm));
                 } else {
                     croak("Unexpected DCS directory field '%s'\n", key);
                 }
             } else {
                 croak("DCS directory field '%s' is not a string\n", key);
             }
         } /* End while: all keys */

         /* Check that the required entries are present */
         if (! dcs_node_info.ldb[0])
             croak("Required parameter 'Database' is missing\n");
         if (! dcs_node_info.tdb[0])
             croak("Required parameter 'Target' is missing\n");

         /* Make the call and return the result */
         sqlegdad(&dcs_node_info, &global_sqlca);
         if (global_sqlca.sqlcode != SQL_RC_OK) {
             warn("Call to sqlegdad() failed with sqlcode %d",
                  global_sqlca.sqlcode);
             XSRETURN_UNDEF;
         } else {
             SV *Return;

             Return = sv_newmortal();
             sv_setiv(Return, 1);
             XPUSHs(Return);
         }
     }


#
# Uncatalog a DCS database
#
# Parameters:
# - (Local) Database name
# Returns:
# - Boolean
#
void
sqlegdel(database)
    char *database

    PPCODE:
    {
        struct sql_dir_entry dcs_node_info = { SQL_DCS_STR_ID, 0, 0, "", "", "", "", "" };

        if (strlen(database) > sizeof(dcs_node_info.ldb))
            croak("Database name '%'s is too long - maximum is '%d' characters\n", database, sizeof(dcs_node_info.ldb));
        strncpy(dcs_node_info.ldb, database, sizeof(dcs_node_info.ldb));
        sqlegdel(&dcs_node_info, &global_sqlca);
        if (global_sqlca.sqlcode != SQL_RC_OK) {
            warn("Call to sqlegdel() failed with sqlcode %d",
                 global_sqlca.sqlcode);
            XSRETURN_UNDEF;
        } else {
            SV *Return;

            Return = sv_newmortal();
            sv_setiv(Return, 1);
            XPUSHs(Return);
        }
    }


#
# Force one or more applications
#
# Parameters:
# - Ref to array of agent ids / String 'All'
# Returns:
# - Boolean
#
void
sqlefrce(params)
     SV   *params

     PPCODE:
     {
         long       num_agent_ids;
         sqluint32 *agent_ids;

         /*
          * Verify we have a string or an array.
          * - String: must be 'All;
          * - Array: build array of agent ids
          */
         if (!SvROK(params)) {  /* Not a reference - must be string */
             if (SvPOK(params)) {
                 char  *val;
                 STRLEN len;

                 val = SvPV(params, len);
                 if (strcmp(val, "All")) {
                     croak("String input parameter must be 'All'");
                 }
                 num_agent_ids = SQL_ALL_USERS;
                 agent_ids = 0;
             } else {
                 croak("Have non-reference param of type <> string");
             }
         } else if (SvTYPE(SvRV(params)) == SVt_PVAV) {
             AV  *agent_id_array;
             int  counter;

             agent_id_array = (AV*)SvRV(params);
             num_agent_ids = av_len(agent_id_array) + 1; /* Num elements */
             if (num_agent_ids == 0) {
                 croak("Must specify at least one agent id in array");
             }
             Newz(0, agent_ids, num_agent_ids, sqluint32);
             for (counter = 0; counter < num_agent_ids; counter++) {
                 SV **agent_id;

                 agent_id = av_fetch(agent_id_array, counter, FALSE);
                 if (!SvROK(*agent_id) && looks_like_number(*agent_id)) {
                     sqluint32 val = (sqluint32)SvUV(*agent_id);
                     agent_ids[counter] = val;
                 } else {
                     croak("Invalid agent id at array element %d: not a number", counter);
                 }
             }
         } else {
             croak("Have reference parameter of type <> array ref");
         }

         /* Make the actual call */
         sqlefrce(num_agent_ids, agent_ids, SQL_ASYNCH, &global_sqlca);
         Safefree(agent_ids);

         if (global_sqlca.sqlcode == SQL_RC_OK) {
             SV  *Return;

             Return = sv_newmortal();
             sv_setiv(Return, 1);
             XPUSHs(Return);
         } else {
             XSRETURN_UNDEF;
         }
     }

#
# Export data from a table into a file
#
# Parameters:
# - Database name
# - SELECT clause
# - File type (DEL/IXF)
# - Output file name
# - Log file name
# - File options string (for DEL)
# - LOB path(s)  (scalar / array ref / undef)
# - LOB file(s)  (scalar / array ref / undef)
# - Export options hash
# - XML path(s)  (scalar / array ref / undef)
# - XML file(s)  (scalar / array ref / undef)
# Returns:
# - Number of rows exported / -1
#
void
db2Export(db_alias, select_sql, file_type, data_file, msg_file, file_options, lob_paths, lob_files, export_options, xml_paths, xml_files)
    char *db_alias
    char *select_sql
    char *file_type
    char *data_file
    char *msg_file
    char *file_options
    SV   *lob_paths
    SV   *lob_files
    SV   *export_options
    SV   *xml_paths
    SV   *xml_files

    PPCODE:
    {
        int                      error = 0;
        void                    *newz_ptr;
        SV                      *Return;
        struct sqlchar          *filetype_mod = NULL;
        struct sqldcol           data_descriptor;
        struct sqlu_media_list  *lob_path_info, *lob_file_info;
        db2ExportStruct          export_info =
            { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0x00, NULL };
        struct sqllob           *action_string = NULL;
        db2ExportOut             output_info;
#ifdef ADMIN_API_HAVE_EXPORT_XML
        db2Uint16                xml_save_schema;
        db2ExportIn              input_info = { NULL };
        struct sqlu_media_list  *xml_path_info, *xml_file_info;
        SV                      *value;
        char                    *key;
        I32                      keylen;
#endif /* ADMIN_API_HAVE_EXPORT_XML */
        /* Look up the database connection and mark it as active */
        if (check_connection(db_alias) == 0) {
            error = 1;
            goto leave;
        }

        /* Set up all input parameters */
        Newz(0, newz_ptr,
             strlen(select_sql) + sizeof(struct sqllob) + 1, char);
        action_string = newz_ptr;
        action_string->length = strlen(select_sql);
        strcpy(action_string->data, select_sql);

        Newz(0, newz_ptr,
             strlen(file_options) + sizeof(struct sqlchar) + 1, char);
        filetype_mod = newz_ptr;
        filetype_mod->length = strlen(file_options);
        strcpy(filetype_mod->data, file_options);
        data_descriptor.dcolmeth = SQL_METH_D;

        lob_path_info = _build_media_list("lob_path names", lob_paths);
        lob_file_info = _build_media_list("lob file names", lob_files);
        if (lob_file_info) {
            lob_file_info->media_type = SQLU_CLIENT_LOCATION;
        }

        /* XS doesn't like empty lines before an ifdef */
#ifdef ADMIN_API_HAVE_EXPORT_XML
        /* Handle XML Path, file info */
        xml_path_info = _build_media_list("xml_path names", xml_paths);
        xml_file_info = _build_media_list("xml file names", xml_files);
        if (xml_file_info) {
            xml_file_info->media_type = SQLU_CLIENT_LOCATION;
        }

        /*
         * Handle the export_options hash (V9.1)
         * - XmlSaveSchema
         * - RestartCount
         * - SkipCount
         * - CommitCount

Admin.xs  view on Meta::CPAN

            Safefree(lob_file_info);
        }
#ifdef ADMIN_API_HAVE_EXPORT_XML
        if (xml_path_info) {
            Safefree(xml_path_info->target.media);
            Safefree(xml_path_info);
        }
        if (xml_file_info) {
            Safefree(xml_file_info->target.media);
            Safefree(xml_file_info);
        }
#endif
        if (global_sqlca.sqlcode < 0) /* 0: OK, > 0: warning */
            error = 1;

    leave:
        /* Return rows exported if okay, -1 on error */
        Return = sv_newmortal();
        if (error) {
            sv_setiv(Return, -1);
        } else {
            /* FIXME: rows exported is signed 64-bit value, does this fit? */
            sv_setuv(Return, (UV)output_info.oRowsExported);
        }
        XPUSHs(Return);
    }


#
# Import data from a file into a table (insert / replace)
#
#
# Parameters:
# - Database alias
# - Import SQL string
# - File type (DEL/IXF)
# - Source file name
# - Input columns (array ref / undef)
# - Message file
# - File option string
# - Import options (hash reference)
# - LOB path(s)  (scalar / array ref / undef)
# - XML path(s)  (scalar / array ref / undef)
#
# Returns:
# - Ref to hash with rows imported/replaced/failed/etc
#
void
db2Import(db_alias, import_sql, file_type, data_file, input_columns, msg_file, file_options, import_options, lob_paths, xml_paths)
     char *db_alias;
     char *import_sql
     char *file_type
     char *data_file
     SV   *input_columns
     char *msg_file
     char *file_options
     SV   *import_options
     SV   *lob_paths
     SV   *xml_paths

     PPCODE:
     {
         int                      error = 0;
         SV                      *value;
         struct sqlchar          *filetype_mod = NULL;
#ifdef ADMIN_API_HAVE_IMPORT_LONG_ACTION /* DB2 V9.5 and up */
         struct sqllob           *action_string = NULL;
#else /* DB2 V9.1 and before */
         struct sqlchar          *action_string = NULL;
#endif
         struct sqldcol          *data_descriptor = NULL;
         char                    *key;
         void                    *newz_ptr;
         I32                      keylen;
         struct sqlu_media_list  *lob_path_info;
         db2int32                 commit_count = DB2IMPORT_COMMIT_AUTO;
         db2ImportIn              input_info = { 0, 0, 0, NULL, 0, 0, 0 };
         db2ImportOut             output_info = { 0, 0, 0, 0, 0, 0 };
         db2ImportStruct          import_info =
             { NULL, NULL, NULL, NULL, NULL, NULL, NULL,
               SQLU_INITIAL, NULL, NULL, NULL };
#ifdef ADMIN_API_HAVE_IMPORT_XML
         db2Uint16                xml_parse;
         struct sqlu_media_list  *xml_path_info;
#endif

         /* Look up the database connection and mark it as active */
         if (check_connection(db_alias) == 0) {
             error = 1;
             goto leave;
         }

         /* Check input_columns is valid */
         if ((!SvROK(input_columns)) ||
             (SvTYPE(SvRV(input_columns)) != SVt_PVAV)) {
             croak("Array reference expected for parameter 'input_columns'");
         }
         /* Check import_options is valid */
         if ((!SvROK(import_options)) ||
             (SvTYPE(SvRV(import_options)) != SVt_PVHV)) {
             croak("Hash reference expected for parameter 'import_options'");
         }

         /* Set up all input parameters */
#ifdef ADMIN_API_HAVE_IMPORT_LONG_ACTION /* DB2 V9.5 and up */
         Newz(0, newz_ptr,
              strlen(import_sql) + sizeof(struct sqllob) + 1, char);
#else /* DB2 V9.1 and before */
         Newz(0, newz_ptr,
              strlen(import_sql) + sizeof(struct sqlchar) + 1, char);
#endif
         action_string = newz_ptr;
         action_string->length = strlen(import_sql);
         strcpy(action_string->data, import_sql);

         Newz(0, newz_ptr,
              strlen(file_options) + sizeof(struct sqlchar) + 1, char);
         filetype_mod = newz_ptr;
         filetype_mod->length = strlen(file_options);
         strcpy(filetype_mod->data, file_options);
         lob_path_info = _build_media_list("lob path names", lob_paths);

Admin.xs  view on Meta::CPAN

             hv_store(retval, "RowsRead", 8,
                      newSVuv(output_info.oRowsRead), FALSE);
             hv_store(retval, "RowsSkipped", 11,
                      newSVuv(output_info.oRowsSkipped), FALSE);
             hv_store(retval, "RowsInserted", 12,
                      newSVuv(output_info.oRowsInserted), FALSE);
             hv_store(retval, "RowsUpdated", 11,
                      newSVuv(output_info.oRowsUpdated), FALSE);
             hv_store(retval, "RowsRejected", 12,
                      newSVuv(output_info.oRowsRejected), FALSE);
             hv_store(retval, "RowsCommitted", 13,
                      newSVuv(output_info.oRowsCommitted), FALSE);
             Return = newRV_noinc((SV*)retval);
             XPUSHs(Return);
         } else {
             XSRETURN_UNDEF;
         }
     }


#
# Load data into a table
#
# Parameters:
# - Database alias
# - Ref to array with column names (IXF file) / column offsets (DEL file) [opt]
# - Load action string
# - Source type (DEL/IXF/Statement)
# - Media type (Server/Client)
# - Source List (file name / array of file names / SQL statement)
# - CopyList (directory)
# - Message file
# - Tempfiles path (empty string: default)
# - File option string
# - Load options (hash reference)
# - DPF options (hash reference)
# - LOB path(s)  (scalar / array ref / undef)
# - XML path(s)  (scalar / array ref / undef)
#
# Returns:
# - Ref to hash with rows loaded/replaced/failed/etc
# - Ref to array with DPF details
#
void
db2Load(db_alias, load_action_string, input_columns, source_type, media_type, source_list, copy_list, msg_file, tempfiles_path, file_options, load_options, dpf_options, lob_paths, xml_paths)
     char *db_alias;
     char *load_action_string
     SV   *input_columns
     char *source_type
     char *media_type
     SV   *source_list
     char *copy_list
     char *msg_file
     char *tempfiles_path
     char *file_options
     SV   *load_options
     SV   *dpf_options
     SV   *lob_paths
     SV   *xml_paths

     PPCODE:
     {
         int                           error = 0;
         SV                           *value;
         char                         *key;
         void                         *newz_ptr;
         I32                           keylen;
         struct sqlu_media_list       *source_media_info = NULL;
         struct sqlu_media_list       *lob_path_info = NULL;
         struct sqlu_media_list        copy_media_info = { 0 };
         struct sqlu_location_entry    copy_location_info = { 0 };
         struct sqlu_statement_entry   source_statement_info = { 0 };
#ifdef ADMIN_API_HAVE_LOAD_LONG_ACTION /* DB2 V9.5 and up */
         struct sqllob                *action_string = NULL;
#else /* DB2 V9.1 and before */
         struct sqlchar               *action_string = NULL;
#endif
         struct sqlchar               *filetype_mod = NULL;
         struct sqldcol               *data_descriptor = NULL;
         db2LoadIn                     input_info =
             { 0, 0, NULL, 0, 0, 0, /* iSortBufferSize */
               0, FALSE, 0, 0, SQLU_RECOVERABLE_LOAD,  /*iNonRecoverable */
               SQLU_INX_AUTOSELECT, /* iIndexingMode */
               SQLU_ALLOW_NO_ACCESS, FALSE, /* iLockWithForce */
               SQLU_CHECK_PENDING_CASCADE_DEFERRED, /* iCheckPending */
               ' ', SQLU_STATS_NONE };
         db2LoadOut                    output_info = { 0, 0, 0, 0, 0, 0 };

         /* Elements for db2PartLoadIn */
         int                           have_dpf_options = 0;
         db2LoadNodeList               pi_OutputNodes = { NULL, 0 };
         db2LoadNodeList               pi_PartitioningNodes = { NULL, 0 };
         db2Uint16                     pi_MaxNumPartAgents;
         db2Uint16                     pi_IsolatePartErrors;
         db2Uint16                     pi_StatusInterval;
         db2LoadPortRange              pi_PortRange = { 0, 0 };
         db2Uint16                     pi_CheckTruncation;
         db2Uint16                     pi_Trace;
         db2Uint16                     pi_Newline;
         db2Uint16                     pi_OmitHeader;
         SQL_PDB_NODE_TYPE             pi_RunStatDBPartNum;

         db2PartLoadIn                 part_input_info =
             { NULL, NULL, NULL, NULL, NULL, /* piPartitioningNodes */
               NULL, NULL, NULL, NULL, NULL, /* piPortRange */
               NULL, NULL, NULL, NULL, NULL, /* piNewline */
               NULL, NULL, NULL };
         db2PartLoadOut                part_output_info =
             { 0, 0, 0, NULL, 0, 0 };
         db2LoadStruct                 load_info =
             { NULL, NULL, NULL, NULL, NULL, /* piFileType */
               NULL, NULL, NULL, NULL, NULL, /* piCopyTargetList */
               NULL, NULL, NULL, NULL, NULL, /* poPartLoadInfoOut */
               SQLU_INITIAL };
#ifdef ADMIN_API_HAVE_LOAD_XML
         db2Uint16                      xml_parse;
         struct sqlu_media_list        *xml_path_info;
#endif

         /* Look up the database connection and mark it as active */
         if (check_connection(db_alias) == 0) {

Admin.xs  view on Meta::CPAN

                                  newSVuv(ai->oNodeNum), FALSE);
                         switch (ai->oAgentType) {
                         case DB2LOAD_LOAD_AGENT:
                             ptr = "Load";
                             break;
                         case DB2LOAD_PARTITIONING_AGENT:
                             ptr = "Partitioning";
                             break;
                         case DB2LOAD_PRE_PARTITIONING_AGENT:
                             ptr = "Pre-partitioning";
                             break;
                         case DB2LOAD_FILE_TRANSFER_AGENT:
                             ptr = "File Transfer";
                             break;
                         case DB2LOAD_LOAD_TO_FILE_AGENT:
                             ptr = "Load To File";
                             break;
                         default:
                             ptr = "(unknown agent type)";
                         }
                         hv_store(agent_elem, "AgentType", 9,
                                  newSVpv(ptr, strlen(ptr)), FALSE);

                         av_push(agent_array, newRV_noinc((SV*)agent_elem));
                     }
                     hv_store(part_retval, "AgentInfo", 9,
                              newRV_noinc((SV*)agent_array), FALSE);
                 }
                 Safefree(part_output_info.poAgentInfoList);
             }

             /* Push both return values. */
             Return = newRV_noinc((SV*)retval);
             XPUSHs(Return);

             PartReturn = newRV_noinc((SV*)part_retval);
             XPUSHs(PartReturn);
         } else {
             XSRETURN_UNDEF;
         }
     }


#
# Query loads going on for a table.
#
# Parameters:
# - Table (schema.table)
# - Message type (All/None/New)
# - Message file
#
# Returns:
# - Ref to hash with load status
#
void
db2LoadQuery(table_name, msg_type, msg_file)
     char *table_name
     char *msg_type
     char *msg_file

     PPCODE:
     {
         db2LoadQueryStruct       query_info;
         db2LoadQueryOutputStruct output_info;

         memset(&query_info, 0, sizeof(query_info));
         memset(&output_info, 0, sizeof(output_info));
         query_info.iStringType = DB2LOADQUERY_TABLENAME;
         query_info.piString = table_name;
         query_info.poOutputStruct = &output_info;
         query_info.piLocalMessageFile = msg_file;

         if (strEQ(msg_type, "All")) {
             query_info.iShowLoadMessages = DB2LOADQUERY_SHOW_ALL_MSGS;
         } else if (strEQ(msg_type, "No") || strEQ(msg_type, "None")) {
             query_info.iShowLoadMessages = DB2LOADQUERY_SHOW_NO_MSGS;
         } else if (strEQ(msg_type, "New")) {
             query_info.iShowLoadMessages = DB2LOADQUERY_SHOW_NEW_MSGS;
         } else {
             croak("Invalid message type '%s' - expected 'All', 'None' or 'New'\n", msg_type);
         }

         db2LoadQuery(DB2_VERSION_ENUM, &query_info, &global_sqlca);
         /* Return a hash with load query details if okay, undef on error */
         if (global_sqlca.sqlcode >= 0) { /* 0: OK, > 0: warning */
             HV   *retval;
             SV   *Return;
             char *ptr;

             retval = (HV*)sv_2mortal((SV*)newHV());
             hv_store(retval, "RowsRead", 8,
                      newSVuv(output_info.oRowsRead), FALSE);
             hv_store(retval, "RowsSkipped", 11,
                      newSVuv(output_info.oRowsSkipped), FALSE);
             hv_store(retval, "RowsCommitted", 13,
                      newSVuv(output_info.oRowsCommitted), FALSE);
             hv_store(retval, "RowsLoaded", 10,
                      newSVuv(output_info.oRowsLoaded), FALSE);
             hv_store(retval, "RowsRejected", 12,
                      newSVuv(output_info.oRowsRejected), FALSE);
             hv_store(retval, "RowsDeleted", 11,
                      newSVuv(output_info.oRowsDeleted), FALSE);
             hv_store(retval, "CurrentIndex", 12,
                      newSVuv(output_info.oCurrentIndex), FALSE);
             hv_store(retval, "NumTotalIndexes", 15,
                      newSVuv(output_info.oNumTotalIndexes), FALSE);
             hv_store(retval, "CurrentMPPNode", 14,
                      newSVuv(output_info.oCurrentMPPNode), FALSE);
             hv_store(retval, "LoadRestarted", 13,
                      newSVuv(output_info.oLoadRestarted), FALSE);
             switch(output_info.oWhichPhase) {
             case 0:
                 ptr = NULL;    /* Not set */
                 break;
             case DB2LOADQUERY_LOAD_PHASE:
                 ptr = "Load Phase";
                 break;
             case DB2LOADQUERY_BUILD_PHASE:
                 ptr = "Build Phase";
                 break;
             case DB2LOADQUERY_DELETE_PHASE:

Admin.xs  view on Meta::CPAN

                 hv_store(retval, "WhichPhase", 10,
                          newSVpv(ptr, strlen(ptr)), FALSE);
             }
             hv_store(retval, "WarningCount", 12,
                      newSVuv(output_info.oWarningCount), FALSE);
             switch(output_info.oTableState) {
             case DB2LOADQUERY_NORMAL:
                 ptr = "Normal";
                 break;
             case DB2LOADQUERY_CHECK_PENDING:
                 ptr = "Check Pending";
                 break;
             case DB2LOADQUERY_LOAD_IN_PROGRESS:
                 ptr = "Load In Progress";
                 break;
             case DB2LOADQUERY_LOAD_PENDING:
                 ptr = "Load Pending";
                 break;
             case DB2LOADQUERY_READ_ACCESS:
                 ptr = "Read Access";
                 break;
             case DB2LOADQUERY_NOTAVAILABLE:
                 ptr = "Not Available";
                 break;
             case DB2LOADQUERY_NO_LOAD_RESTART:
                 ptr = "Load Restart";
                 break;
             case DB2LOADQUERY_TYPE1_INDEXES:
                 ptr = "Type 1 Indexes";
                 break;
             default:
                 ptr = "(unknown table state)";
             }
             hv_store(retval, "TableState", 10,
                      newSVpv(ptr, strlen(ptr)), FALSE);
             Return = newRV_noinc((SV*)retval);
             XPUSHs(Return);
         } else {
             XSRETURN_UNDEF;
         }
     }



#
# Rebind a package
#
# Parameters:
# - Database name
# - Qualified package name (schema.package)
# - Ref to hash with options
# Returns:
# - Boolean
#
void
sqlarbnd(dbname, package, options)
    char *dbname
    char *package
    SV   *options

    PPCODE:
    {
        struct sqlopt  *rebind_options = NULL;
        int             num_opts, rc, error = 0;

        rc = check_connection(dbname);
        if (rc == 0) {
            error = 1;
            goto leave;
        }

        if ((!SvROK(options)) ||
            (SvTYPE(SvRV(options)) != SVt_PVHV)) {
            croak("Hash reference expected for parameter 'options'");
        }

        /*
         * Iterate over the options hash and extract keys matching:
         * - Version => Integer
         * - Resolve => Any / Conservative
         * - ReOpt => None / Once / Always
         */
        num_opts = HvKEYS((HV*)SvRV(options));
        if (num_opts) {
            char *key;
            void *newz_ptr;
            I32   keylen;
            SV   *value;
            int   offset = 0;

            Newz(0, newz_ptr,
                 sizeof(struct sqlopt) + num_opts * sizeof(struct sqloptions),
                 char);
            rebind_options = newz_ptr;
            rebind_options->header.allocated = num_opts;
            rebind_options->header.used = num_opts;

            (void)hv_iterinit((HV*)SvRV(options));
            while ((value = hv_iternextsv((HV*)SvRV(options),
                                          (char **)&key, &keylen))) {
                if (strEQ(key, "Version")) { /* Number */
                    if ((!SvROK(value)) && looks_like_number(value)) {
                        rebind_options->option[offset].type = SQL_VERSION_OPT;
                        rebind_options->option[offset].val = SvIV(value);
                        offset++;
                    } else {
                        croak("Illegal value for Options key '%s': not a number\n", key);
                    }
                } else if (strEQ(key, "Resolve")) {
                    if (SvPOK(value)) {
                        char   *val;
                        STRLEN  len;
                        int     opt_val = SQL_RESOLVE_ANY;

                        val = SvPV(value, len);
                        if (strEQ(val, "Any")) {
                            opt_val = SQL_RESOLVE_ANY;
                        } else if (strEQ(val, "Conservative")) {
                            opt_val = SQL_RESOLVE_CONSERVATIVE;
                        } else {
                            croak("Illegal value '%s' for Options key '%s': expected 'Any' or 'Conservative'", val, key);

Admin.xs  view on Meta::CPAN

                            opt_val = SQL_REOPT_ONCE;
                        } else if (strEQ(val, "Always")) {
                            opt_val = SQL_REOPT_ALWAYS;
                        } else {
                            croak("Illegal value '%s' for Options key '%s': expected 'None', 'Once' or 'Always'", val, key);
                        }
                        rebind_options->option[offset].type = SQL_REOPT_OPT;
                        rebind_options->option[offset].val = opt_val;
                        offset++;
                    } else {
                        croak("Illegal value for Options key '%s': not a string\n", key);
                    }
                } else {
                    croak("Unexpected Options key '%s'", key);
                }
            } /* End: each hash entry */
        } /* End if: have options */

        /* Perform actual rebind call */
        sqlarbnd(package, &global_sqlca, rebind_options);
        Safefree(rebind_options);
        if (global_sqlca.sqlcode != SQL_RC_OK) {
            /* warn("sqlarbnd() returned with error code %d\n", global_sqlca.sqlcode); */
            error = 1;
        }

        /* Commit on the current database handle */
        SQLEndTran(SQL_HANDLE_DBC, cur_db_handle, SQL_COMMIT);

    leave:
        if (error == 0) {
            SV  *Return;

            Return = sv_newmortal();
            sv_setiv(Return, 1);
            XPUSHs(Return);
        } else {
            XSRETURN_UNDEF;
        }
    }


#
# List database history
#
# Parameters:
# - Database name
# - Action
# - Object name (optional)
# - Start timestamp (optional)
# Returns:
# - Ref to array with history records / undef on error
#
void
db2ListHistory(dbname, action, obj_name, start_time)
    char *dbname
    char *action
    char *obj_name
    char *start_time

    PPCODE:
    {
        struct db2HistoryOpenStruct      open_info =
            { NULL, NULL, NULL, 0, 0, DB2HISTORY_LIST_HISTORY, 0 };
        struct db2HistoryGetEntryStruct  entry_info;
        struct db2HistoryData            entry_data;
        int                              error = 0;
        unsigned int                     counter;
        AV                              *retval;

        /* Translate the action string to an enum */
        if (strEQ(action, "All") || strEQ(action, "History")) {
            open_info.iCallerAction = DB2HISTORY_LIST_HISTORY;
        } else if (strEQ(action, "Backup")) {
            open_info.iCallerAction = DB2HISTORY_LIST_BACKUP;
        } else if (strEQ(action, "RollForward") ||
                   strEQ(action, "Roll Forward")) {
            open_info.iCallerAction = DB2HISTORY_LIST_ROLLFORWARD;
        } else if (strEQ(action, "Reorg")) {
            open_info.iCallerAction = DB2HISTORY_LIST_REORG;
        } else if (strEQ(action, "AlterTablespace") ||
                   strEQ(action, "Alter Tablespace")) {
            open_info.iCallerAction = DB2HISTORY_LIST_ALT_TABLESPACE;
        } else if (strEQ(action, "DropTable") ||
                   strEQ(action, "Drop Table")) {
            open_info.iCallerAction = DB2HISTORY_LIST_DROPPED_TABLE;
        } else if (strEQ(action, "Load")) {
            open_info.iCallerAction = DB2HISTORY_LIST_LOAD;
        } else if (strEQ(action, "RenameTablespace") ||
                   strEQ(action, "Rename Tablespace")) {
            open_info.iCallerAction = DB2HISTORY_LIST_REN_TABLESPACE;
        } else if (strEQ(action, "CreateTablespace") ||
                   strEQ(action, "Create Tablespace") ||
                   strEQ(action, "DropTablespace") ||
                   strEQ(action, "Drop Tablespace")) {
            open_info.iCallerAction = DB2HISTORY_LIST_CRT_TABLESPACE;
        } else if (strEQ(action, "ArchiveLog") ||
                   strEQ(action, "Archive Log")) {
            open_info.iCallerAction = DB2HISTORY_LIST_ARCHIVE_LOG;
        } else {
            croak("Unknown ListHistory action '%s'\n", action);
        }

        open_info.piDatabaseAlias = dbname;
        if (strlen(start_time) > 0)
            open_info.piTimestamp = start_time;
        if (strlen(obj_name) > 0)
            open_info.piObjectName = obj_name;

        /* Open history scan */
        db2HistoryOpenScan(DB2_VERSION_ENUM, &open_info, &global_sqlca);
        if (global_sqlca.sqlcode != SQL_RC_OK) {
            warn("db2HistoryOpenScan() returned with error code %d\n", global_sqlca.sqlcode);
            error = 1;
            goto leave;
        }
        /*
         *      warn("OpenScan returned with %d rows and max %d tablespaces\n",
         *           open_info.oNumRows, open_info.oMaxTbspaces);
         */

Admin.xs  view on Meta::CPAN

                     croak("Illegal value for options key '%s': not a number\n", key);
                 }
             } else {
                 croak("Unknown Runstats options key '%s'\n", key);
             }

             /*
              * In most cases, the hash value is a boolean
              * that indicates a flag bit should be set.
              */
             if (boolean_value && SvTRUE(value))
                 runstats_info.iRunstatsFlags |= bits;
         } /* End each: key/value pair in options hash */

         /*
          * If no flags set and no columns or indexes specified, set
          * "all columns"
          */
         if (runstats_info.iRunstatsFlags == 0 &&
             runstats_info.iNumColumns == 0 &&
             runstats_info.iNumIndexes == 0) {
             runstats_info.iRunstatsFlags = DB2RUNSTATS_ALL_COLUMNS;
         }

         db2Runstats(DB2_VERSION_ENUM, &runstats_info, &global_sqlca);
         if (global_sqlca.sqlcode < 0) /* 0: okay, > 0: warning */
             error = 1;

         /* Commit on the current database handle */
         SQLEndTran(SQL_HANDLE_DBC, cur_db_handle, SQL_COMMIT);

     leave:
         Safefree(column_info); /* Okay if not allocated */
         Safefree(runstats_info.piColumnList); /* Okay if not set */
         Safefree(runstats_info.piIndexList); /* Okay if not set */
         RETVAL = error;
    }
OUTPUT:
     RETVAL


#
# Set and get client information
#
# Parameters:
# - Database name
# - Hash reference with optional keys:
#   - ClientUserid
#   - Workstation
#   - Application
#   - AccountingString
# Returns:
# - Hash reference with the same keys, but now all present
#   (unless empty strings)
#
void
db2ClientInfo(dbname, client_info)
    char *dbname
    SV   *client_info

    PPCODE:
    {
        struct sqle_client_info  client_app_info[4]; /* Max no of attributes */
        HV                      *info, *retval;
        I32                      keylen;
        SV                      *value, *Return;
        char                    *key;
        int                      no_items = 0;
        unsigned int             len;

        if (!SvROK(client_info))
            croak("Reference expected for client_info");
        if (SvTYPE(SvRV(client_info)) != SVt_PVHV)
            croak("Hash reference expected for client_info");
        info = (HV*)SvRV(client_info);

        /*
         * Iterate over all hash key/value pairs, so we can
         * check if anything unknown is specified.
         *
         * - ClientUserid
         * - Workstation
         * - Application
         * - AccountingString
         */
        while ((value = hv_iternextsv(info, (char **)&key, &keylen))) {
            unsigned short  type, maxlen;
            char           *buf;
            STRLEN          len;

            if (strEQ(key, "ClientUserid")) {
                type = SQLE_CLIENT_INFO_USERID;
                maxlen = SQLE_CLIENT_USERID_MAX_LEN;
            } else if (strEQ(key, "Workstation")) {
                type = SQLE_CLIENT_INFO_WRKSTNNAME;
                maxlen = SQLE_CLIENT_WRKSTNNAME_MAX_LEN;
            } else if (strEQ(key, "Application")) {
                type = SQLE_CLIENT_INFO_APPLNAME;
                maxlen = SQLE_CLIENT_APPLNAME_MAX_LEN;
            } else if (strEQ(key, "AccountingString")) {
                type = SQLE_CLIENT_INFO_ACCTSTR;
                maxlen = SQLE_CLIENT_ACCTSTR_MAX_LEN;
            } else {
                croak("Invalid client info key '%s'", key);
            }
            buf = SvPV(value, len);
            if (len > maxlen) {
                croak("client_info element '%s' data value too large - maximum %d bytes, this is %d bytes", key, maxlen, len);
            }
            client_app_info[no_items].type = type;
            Newz(0, client_app_info[no_items].pValue, len+1, char);
            strcpy(client_app_info[no_items].pValue, buf);
            client_app_info[no_items].length = len;
            no_items++;
        } /* End while: each key/value pair */

        /* If one or more items present, set client information */
        if (no_items) {
            sqleseti(strlen(dbname), dbname, no_items, client_app_info,
                    &global_sqlca);
            if (global_sqlca.sqlcode != 0) {

Admin.xs  view on Meta::CPAN

        Newz(0, client_app_info[3].pValue, SQLE_CLIENT_ACCTSTR_MAX_LEN + 1,
             char);
        no_items = 4;
        sqleqryi(strlen(dbname), dbname, no_items, client_app_info,
                 &global_sqlca);
        if (global_sqlca.sqlcode != 0) {
            croak("Failed to get client information - sqleqryi() failed with sqlcode %d\n", global_sqlca.sqlcode);
        }

        /* Create return value */
        retval = (HV*)sv_2mortal((SV*)newHV());
        len = client_app_info[0].length;
        if (len) {
            hv_store(retval, "ClientUserid", 12,
                     newSVpvn(client_app_info[0].pValue, len), FALSE);
        }

        len = client_app_info[1].length;
        if (len) {
            hv_store(retval, "Workstation", 11,
                     newSVpvn(client_app_info[1].pValue, len), FALSE);
        }

        len = client_app_info[2].length;
        if (len) {
            hv_store(retval, "Application", 11,
                     newSVpvn(client_app_info[2].pValue, len), FALSE);
        }

        len = client_app_info[3].length;
        if (len) {
            hv_store(retval, "AccountingString", 16,
                     newSVpvn(client_app_info[3].pValue, len), FALSE);
        }
        no_items = 4;
        while (--no_items >= 0)
            Safefree(client_app_info[no_items].pValue);
        Return = newRV_noinc((SV*)retval);
        XPUSHs(Return);
    }


#
# Perform a backup
#
# Parameters:
# - Database name
# - Target (ref to array of strings)
# - Tablespaces (ref to array of tablespaces)
# - Options (hash reference)
# Returns:
# - Ref to hash with ApplicationId/Timestamp/BackupSize/SQLCode/NodeInfo/...
#
void
db2Backup(db_alias, target, tbspaces, options)
     char *db_alias;
     SV   *target;
     SV   *tbspaces;
     SV   *options;

     PPCODE:
     {
         db2BackupStruct            backup_info;
         db2MediaListStruct         location_info = { NULL, 0, 0 };
         char                     **locations = NULL;
         db2TablespaceStruct        tablespace_info = { NULL, 0 };
         char                     **tablespaces = NULL;
#ifdef DB2BACKUP_MPP
         db2NodeType               *node_list = NULL;
         db2BackupMPPOutputStruct  *mpp_output = NULL;
#endif /* DB2BACKUP_MPP */
         SV                        *value;
         char                      *key;
         I32                        keylen;

         /* Check target is valid */
         if ((!SvROK(target)) ||
             (SvTYPE(SvRV(target)) != SVt_PVAV)) {
             croak("Array reference expected for parameter 'target'");
         }
         /* Check tablespaces is valid */
         if ((!SvROK(tbspaces)) ||
             (SvTYPE(SvRV(tbspaces)) != SVt_PVAV)) {
             croak("Array reference expected for parameter 'tbspaces'");
         }
         /* Check options is valid */
         if ((!SvROK(options)) ||
             (SvTYPE(SvRV(options)) != SVt_PVHV)) {
             croak("Hash reference expected for parameter 'options'");
         }

         /*
          * The backup structure differs between DB2 releases,
          * so it's hard to write an initializer.  We will
          * just zero it.
          */
         memset(&backup_info, 0, sizeof(backup_info));
         backup_info.piDBAlias = db_alias;

         /* Set up target */
         backup_info.piMediaList = &location_info;
         backup_info.iCallerAction = DB2BACKUP_NOINTERRUPT; /* See Action below */
         location_info.locationType = SQLU_LOCAL_MEDIA;  /* See TargetType below */
         if (av_len((AV*)SvRV(target)) >= 0) {
             AV     *media;
             I32     no_entries, counter;

             media = (AV*)SvRV(target);
             no_entries = av_len(media) + 1;
             location_info.numLocations = no_entries;
             Newz(0, locations, no_entries, char *);
             location_info.locations = locations;

             for (counter = 0; counter < no_entries; counter++) {
                 SV **array_elem;

                 array_elem = av_fetch(media, counter, FALSE);
                 if (SvPOK(*array_elem)) {
                     char   *val;
                     STRLEN  len;

Admin.xs  view on Meta::CPAN

                         break;

                     node_elem = newHV();
                     hv_store(node_elem, "NodeNum", 7,
                              newSVuv(ni->nodeNumber), FALSE);
                     hv_store(node_elem, "BackupSize", 10,
                              newSVuv(ni->backupSize), FALSE);
                     hv_store(node_elem, "SQLCode", 7,
                              newSViv(ni->sqlca.sqlcode), FALSE);
                     status = sqlaintp(buffer, MESSAGE_BUFFER_SIZE, 0,
                                       &ni->sqlca);
                     if (status > 0) {
                         hv_store(node_elem, "Message", 7,
                                  newSVpv(buffer, status), FALSE);
                     }
                     status = sqlogstt(buffer, MESSAGE_BUFFER_SIZE, 0,
                                       ni->sqlca.sqlstate);
                     if (status > 0) {
                         hv_store(node_elem, "State", 5,
                                  newSVpv(buffer, status), FALSE);
                     }
                     av_push(part_retval, newRV_noinc((SV*)node_elem));
                 } /* End: for each node */

                 Safefree(mpp_output);
                 Safefree(node_list);
             } /* End: if have node output */
#endif /* DB2BACKUP_MPP */

             /* Push both return values. */
             Return = newRV_noinc((SV*)retval);
             XPUSHs(Return);
         }
     }


#
# Return the SQL code for the global sqlca data structure
#
#   0: okay
# > 0: warning
# < 0: error
#
int
sqlcode()
CODE:
     RETVAL = global_sqlca.sqlcode;
OUTPUT:
     RETVAL


#
# Display the error message for the global sqlca data structure
#
# Returns:
# - String with error message / undef
#
void
sqlaintp()

     PPCODE:
     {
         char buffer[MESSAGE_BUFFER_SIZE];
         int  status;
         SV  *Return;

         status = sqlaintp(buffer, MESSAGE_BUFFER_SIZE, 0, &global_sqlca);
         /* FIXME: Look at status, resize, ... */
         if (status > 0) {
             Return = sv_newmortal();
             sv_setpvn(Return, buffer, status);
             XPUSHs(Return);
         } else {
             XSRETURN_UNDEF;
         }
     }


#
# Display the status code message for the global sqlca data structure
#
# Returns:
# - String with status code message / undef
#
# NOTE: The C version takes an int (sqlca->sqlstate), but we use
#       a sqlca struct to make it look like sqlaintp.
#       as IBM does not document it...
#
void
sqlogstt()

     PPCODE:
     {
         char buffer[MESSAGE_BUFFER_SIZE];
         int  status;
         SV  *Return;

         status = sqlogstt(buffer, MESSAGE_BUFFER_SIZE, 0,
                           global_sqlca.sqlstate);
         /* FIXME: Look at status, resize, ... */
         if (status > 0) {
             Return = sv_newmortal();
             sv_setpvn(Return, buffer, status);
             XPUSHs(Return);
         } else {
             XSRETURN_UNDEF;
         }
     }



( run in 1.141 second using v1.01-cache-2.11-cpan-71847e10f99 )