DB2-Admin
view release on metacpan or search on metacpan
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);
&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);
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;
/* 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);
}
} 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;
}
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) {
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);
}
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");
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
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);
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) {
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:
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);
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);
*/
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) {
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;
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 )