IBM / node-odbc

ODBC bindings for node
MIT License
148 stars 77 forks source link

odbc

An asynchronous interface for Node.js to unixODBC and its supported drivers.


Requirements


Node.js Version Support

This package is a native addon written in C++ using node-addon-api. Like node-addon-api, node-odbc only supports the active LTS Node.js versions.

Currently supported versions include:


Installation

Three main steps must be done before node-odbc can interact with your database:

When all these steps have been completed, install node-odbc into your Node.js project by using:

npm install odbc

Debugging

This package used to contain its own method of tracing ODBC calls, which was enabled by recompiling the package with DEBUG defined. Because this information was almost wholly redundant with existing methods of tracing available through ODBC driver managers, it was removed in v2.4.0.

Instead, tracing should be enabled through your driver manager, and that information can be analyzed and included with the description of issues encountered.

Drivers


Important Changes in 2.0

node-odbc has recently been upgraded from its initial release. The following list highlights the major improvements and potential code-breaking changes.


API

Callbacks or Promises

Every asynchronous function in the Node.js node-odbc package can be called with either a callback Function or a Promise. To use Promises, simply do not pass a callback function (in the API docs below, specified with a callback?). This will return a Promise object than can then be used with .then or the more modern async/await workflow. To use callbacks, simply pass a callback function. For each function explained in the documents below, both Callback and Promise examples are given.

All examples are shown using IBM i Db2 DSNs and queries. Because ODBC is DBMS-agnostic, examples will work as long as the query strings are modified for your particular DBMS.

Result Array

All functions that return a result set do so in an array, where each row in the result set is an entry in the array. The format of data within the row can either be an array or an object, depending on the configuration option passed to the connection.

The result array also contains several properties:

[ { CUSNUM: 938472,
    LSTNAM: 'Henning ',
    INIT: 'G K',
    STREET: '4859 Elm Ave ',
    CITY: 'Dallas',
    STATE: 'TX',
    ZIPCOD: 75217,
    CDTLMT: 5000,
    CHGCOD: 3,
    BALDUE: 37,
    CDTDUE: 0 },
  { CUSNUM: 839283,
    LSTNAM: 'Jones   ',
    INIT: 'B D',
    STREET: '21B NW 135 St',
    CITY: 'Clay  ',
    STATE: 'NY',
    ZIPCOD: 13041,
    CDTLMT: 400,
    CHGCOD: 1,
    BALDUE: 100,
    CDTDUE: 0 },
  statement: 'SELECT * FROM QIWS.QCUSTCDT',
  parameters: [],
  return: undefined,
  count: -1,
  columns: [ { name: 'CUSNUM', dataType: 2 },
    { name: 'LSTNAM', dataType: 1 },
    { name: 'INIT', dataType: 1 },
    { name: 'STREET', dataType: 1 },
    { name: 'CITY', dataType: 1 },
    { name: 'STATE', dataType: 1 },
    { name: 'ZIPCOD', dataType: 2 },
    { name: 'CDTLMT', dataType: 2 },
    { name: 'CHGCOD', dataType: 2 },
    { name: 'BALDUE', dataType: 2 },
    { name: 'CDTDUE', dataType: 2 } ] ]

In this example, two rows are returned, with eleven columns each. The format of these columns is found on the columns property, with their names and dataType (which are integers mapped to SQL data types).

With this result structure, users can iterate over the result set like any old array (in this case, results.length would return 2) while also accessing important information from the SQL call and result set.



Connection

A Connection is your means of connecting to the database through ODBC.

constructor: odbc.connect(connectionString)

In order to get a connection, you must use the .connect function exported from the module. This asynchronously creates a Connection and gives it back to you. Like all asynchronous functions, this can be done either with callback functions or Promises.

Parameters:

Examples:

Promises

const odbc = require('odbc');

async function connectToDatabase() {
    const connection1 = await odbc.connect('DSN=MYDSN');
    // connection1 is now an open Connection

    // or using a configuration object
    const connectionConfig = {
        connectionString: 'DSN=MYDSN',
        connectionTimeout: 10,
        loginTimeout: 10,
    }
    const connection2 = await odbc.connect(connectionConfig);
    // connection2 is now an open Connection
}

connectToDatabase();

Callbacks

const odbc = require('odbc');
odbc.connect(connectionString, (error, connection) => {
    // connection is now an open Connection
});

Once a Connection has been created with odbc.connect, you can use the following functions on the connection:


.query(sql, parameters?, options?, callback?)

Run a query on the database. Can be passed an SQL string with parameter markers ? and an array of parameters to bind to those markers. Returns a result array.

Parameters:

const odbc = require('odbc');
const connection = odbc.connect(connectionString, (error, connection) => {
    connection.query('SELECT * FROM QIWS.QCUSTCDT', (error, result) => {
        if (error) { console.error(error) }
        console.log(result);
    });
});

.callProcedure(catalog, schema, name, parameters?, callback?)

Calls a database procedure, returning the results in a result array.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function callProcedureExample() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    const result = await connection.callProcedure(null, null, 'MY_PROC', [undefined]);
    // result contains an array of results, and has a `parameters` property to access parameters returned by the procedure.
    console.log(result);
}

callProcedureExample();

Callbacks

const odbc = require('odbc');

odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.callProcedure(null, null, 'MY_PROC', [undefined], (error, result) => {
        if (error) { console.error(error) } // handle
        // result contains an array of results, and has a `parameters` property to access parameters returned by the procedure.
        console.log(result);
    });
});

.createStatement(callback?)

Returns a Statement object from the connection.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function statementExample() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    const statement = await connection.createStatement();
    // now have a statement where sql can be prepared, bound, and executed
}

statementExample();

Callbacks

const odbc = require('odbc');

// returns information about all tables in schema MY_SCHEMA
odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.createStatement((error, statement) => {
        if (error) { return; } // handle
        // now have a statement where sql can be prepared, bound, and executed
    });
});

.tables(catalog, schema, table, type, callback?)

Returns information about the table specified in the parameters by calling the ODBC function SQLTables. Values passed to parameters will narrow the result set, while null will include all results of that level.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function getTables() {
    // returns information about all tables in schema MY_SCHEMA
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    const result = await connection.tables(null, 'MY_SCHEMA', null, null);
    console.log(result);
}

getTables();

Callbacks

const odbc = require('odbc');

// returns information about all tables in schema MY_SCHEMA
odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.columns(null, "MY_SCHEMA", null, null, (error, result) => {
        if (error) { return; } // handle
        console.log(result);
    });
});

.columns(catalog, schema, table, column, callback?)

Returns information about the columns specified in the parameters by calling the ODBC function SQLColumns. Values passed to parameters will narrow the result set, while null will include all results of that level.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function getColumns() {
    // returns information about all columns in table MY_SCEHMA.MY_TABLE
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    const result = await connection.columns(null, 'MY_SCHEMA', 'MY_TABLE', null);
    console.log(result);
}

getColumns();

Callbacks

const odbc = require('odbc');

// returns information about all columns in table MY_SCEHMA.MY_TABLE
odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.columns(null, "MY_SCHEMA", "MY_TABLE", null, (error, result) => {
        if (error) { return; } // handle
        console.log(result);
    });
});

.setIsolationLevel(level, callback?)

Sets the transaction isolation level for the connection, which determines what degree of uncommitted changes can be seen. More information about ODBC isolation levels can be found on the official ODBC documentation.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function isolationLevel() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    await connection.setIsolationLevel(odbc.SQL_TXN_READ_COMMITTED);
    // isolation level is now set
}

isolationLevel();

Callbacks

const odbc = require('odbc');

odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.setIsolationLevel(odbc.SQL_TXN_READ_COMMITTED, (error) => {
        if (error) { return; } // handle
        // isolation level is now set
    });
});

.beginTransaction(callback?)

Begins a transaction on the connection. The transaction can be committed by calling .commit or rolled back by calling .rollback. If a connection is closed with an open transaction, it will be rolled back. Connection isolation level will affect the data that other transactions can view mid transaction.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function transaction() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    await connection.beginTransaction();
    // transaction is now open
}

transaction();

Callbacks

const odbc = require('odbc');

odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.beginTransaction((error) => {
        if (error) { return; } // handle
        // transaction is now open
    });
});

.commit(callback?)

Commits an open transaction. If called on a connection that doesn't have an open transaction, will no-op.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function commitTransaction() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    await connection.beginTransaction();
    const insertResult = await connection.query('INSERT INTO MY_TABLE VALUES(1, \'Name\')');
    await connection.commit();
    // INSERT query has now been committed
}

commitTransaction();

Callbacks

const odbc = require('odbc');

odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.beginTransaction((error1) => {
        if (error1) { return; } // handle
        connection.query('INSERT INTO MY_TABLE VALUES(1, \'Name\')', (error2, result) => {
            if (error2) { return; } // handle
            connection.commit((error3) => {
                // INSERT query has now been committed
            })
        })
    });
});

.rollback(callback?)

Rolls back an open transaction. If called on a connection that doesn't have an open transaction, will no-op.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function rollbackTransaction() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    await connection.beginTransaction();
    const insertResult = await connection.query('INSERT INTO MY_TABLE VALUES(1, \'Name\')');
    await connection.rollback();
    // INSERT query has now been rolled back
}

rollbackTransaction();

Callbacks

const odbc = require('odbc');

odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.beginTransaction((error1) => {
        if (error1) { return; } // handle
        connection.query('INSERT INTO MY_TABLE VALUES(1, \'Name\')', (error2, result) => {
            if (error2) { return; } // handle
            connection.rollback((error3) => {
                // INSERT query has now been rolled back
            })
        })
    });
});

.close(callback?)

Closes an open connection. Any transactions on the connection that have not been ended will be rolledback.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function closeConnection() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    // do something with your connection here
    await connection.close();
}

rollbackTransaction();

Callbacks

const odbc = require('odbc');

odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
   // do something with your connection here
   connection.close((error) => {
       if (error) { return; } // handle
       // connection is now closed
   })
});


Pool

constructor: odbc.pool(connectionString)

In order to get a Pool, you must use the .pool function exported from the module. This asynchronously creates a Pool of a number of Connections and returns it to you. Like all asynchronous functions, this can be done either with callback functions or Promises.

Note that odbc.pool will return from callback or Promise as soon as it has created 1 connection. It will continue to spin up Connections and add them to the Pool in the background, but by returning early it will allow you to use the Pool as soon as possible.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function createPool() {
    const pool = await odbc.pool(`${process.env.CONNECTION_STRING}`);
    // can now do something with the Pool
}

createPool();

Callbacks

const odbc = require('odbc');
const pool = odbc.pool('DSN=MyDSN', (error, pool) => {
    // pool now has open connections
});

.connect(callback?)

Returns a Connection object for you to use from the Pool. Doesn't actually open a connection, because they are already open in the pool when .init is called.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function connectExample() {
    const pool = await odbc.pool(`${process.env.CONNECTION_STRING}`);
    const connection = await pool.connect();
    // now have a Connection to do work with
}

connectExample();

Callbacks

const odbc = require('odbc');
odbc.pool(`${process.env.CONNECTION_STRING}`, (error1, pool) => {
    if (error1) { return; } // handle
    pool.connect((error2, connection) => {
        if (error2) { return; } // handle
        // now have a Connection to do work with
    });
});

.query(sql, parameters?, callback?)

Utility function to execute a query on any open connection in the pool. Will get a connection, fire of the query, return the results, and return the connection the the pool.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function queryExample() {
    const pool = await odbc.pool(`${process.env.CONNECTION_STRING}`);
    const result = await pool.query('SELECT * FROM MY_TABLE');
    console.log(result);
}

queryExample();

Callbacks

const odbc = require('odbc');
odbc.pool(`${process.env.CONNECTION_STRING}`, (error1, pool) => {
    if (error1) { return; } // handle
    pool.query('SELECT * FROM MY_TABLE', (error2, result) => {
        if (error2) { return; } // handle
        console.log(result);
    });
});

.close(callback?)

Closes the entire pool of currently unused connections. Will not close connections that are checked-out, but will discard the connections when they are closed with Connection's .close function. After calling close, must create a new Pool sprin up new Connections.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function closeExample() {
    const pool = await odbc.pool(`${process.env.CONNECTION_STRING}`);
    await pool.close();
    // pool is now closed
}

closeExample();

Callbacks

const odbc = require('odbc');

odbc.pool(`${process.env.CONNECTION_STRING}`, (error1, pool) => {
    if (error1) { return; } // handle
    // do something with your pool here
    pool.close((error2) => {
        if (error2) { return; } // handle
        // pool is now closed
    });
});


Statement

A Statement object is created from a Connection, and cannot be created ad hoc with a constructor.

Statements allow you to prepare a commonly used statement, then bind parameters to it multiple times, executing in between.


.prepare(sql, callback?)

Prepares an SQL statement, with or without parameters (?) to bind to.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function prepareExample() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    const statement = await connection.createStatement();
    await statement.prepare('INSERT INTO MY_TABLE VALUES(?, ?)');
    // statement has been prepared, can bind and execute
}

prepareExample();

Callbacks

const odbc = require('odbc');

odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.createStatement((error1, statement) => {
        if (error1) { return; } // handle
        statement.prepare('INSERT INTO MY_TABLE VALUES(?, ?)' (error2) => {
            if (error2) { return; } // handle
            // statement has been prepared, can bind and execute
        });
    });
});

.bind(parameters, callback?)

Binds an array of values to the parameters on the prepared SQL statement. Cannot be called before .prepare.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function bindExample() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    const statement = await connection.createStatement();
    await statement.prepare('INSERT INTO MY_TABLE VALUES(?, ?)');
    // Assuming MY_TABLE has INTEGER and VARCHAR fields.
    await statement.bind([1, 'Name']);
    // statement has been prepared and values bound, can now execute
}

bindExample();

Callbacks

const odbc = require('odbc');

odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.createStatement((error1, statement) => {
        if (error1) { return; } // handle
        statement.prepare('INSERT INTO MY_TABLE VALUES(?, ?)' (error2) => {
            if (error2) { return; } // handle
            // Assuming MY_TABLE has INTEGER and VARCHAR fields.
            statement.bind([1, 'Name'], (error3) => {
                if (error3) { return; } // handle
                // statement has been prepared and values bound, can now execute
            });
        });
    });
});

.execute(options?, callback?)

Executes the prepared and optionally bound SQL statement.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function executeExample() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    const statement = await connection.createStatement();
    await statement.prepare('INSERT INTO MY_TABLE VALUES(?, ?)');
    // Assuming MY_TABLE has INTEGER and VARCHAR fields.
    await statement.bind([1, 'Name']);
    const result = await statement.execute();
    console.log(result);

}

executeExample();

Callbacks

const odbc = require('odbc');

odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.createStatement((error1, statement) => {
        if (error1) { return; } // handle
        statement.prepare('INSERT INTO MY_TABLE VALUES(?, ?)' (error2) => {
            if (error2) { return; } // handle
            // Assuming MY_TABLE has INTEGER and VARCHAR fields.
            statement.bind([1, 'Name'], (error3) => {
                if (error3) { return; } // handle
                statement.execute((error4, result) => {
                    if (error4) { return; } // handle
                    console.log(result);
                })
            });
        });
    });
});

.close(callback?)

Closes the Statement, freeing the statement handle. Running functions on the statement after closing will result in an error.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function executeExample() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    const statement = await connection.createStatement();
    await statement.prepare('INSERT INTO MY_TABLE VALUES(?, ?)');
    // Assuming MY_TABLE has INTEGER and VARCHAR fields.
    await statement.bind([1, 'Name']);
    const result = await statement.execute();
    console.log(result);
    await statement.close();
}

executeExample();

Callbacks

const odbc = require('odbc');

odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.createStatement((error1, statement) => {
        if (error1) { return; } // handle
        statement.prepare('INSERT INTO MY_TABLE VALUES(?, ?)' (error2) => {
            if (error2) { return; } // handle
            // Assuming MY_TABLE has INTEGER and VARCHAR fields.
            statement.bind([1, 'Name'], (error3) => {
                if (error3) { return; } // handle
                statement.execute((error4, result) => {
                    if (error4) { return; } // handle
                    console.log(result);
                    statement.close((error5) => {
                        if (error5) { return; } // handle
                        // statement closed successfully
                    })
                })
            });
        });
    });
});


Cursor

A Cursor object is created from a Connection when running a query, and cannot be created ad hoc with a constructor.

Cursors allow you to fetch piecemeal instead of retrieving all rows at once. The fetch size is set on the query options, and then a Cursor is returned from the query instead of a result set. .fetch is then called to retrieve the result set by the fetch size.


.fetch(callback?)

Asynchronously returns the next chunk of rows from the result set and returns them as a Result object.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function cursorExample() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    const cursor = await connection.query('SELECT * FROM MY_TABLE', { cursor: true, fetchSize: 3 });
    const result = await cursor.fetch();
    // Now have a results array of size 3 (or less) that we can use
    await cursor.close();
}

cursorExample();

Callbacks

const odbc = require('odbc');

odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.query('SELECT * FROM MY_TABLE', { cursor: true, fetchSize: 3 }, (error1, cursor) => {
        if (error1) { return; } // handle
        cursor.fetch((error2, results) => {
            if (error2) { return; } // handle
            // Now have a results array of size 3 (or less) that we can use
            cursor.close((error3) => {
                if (error3) { return; } // handle
                // cursor now closed, now do more work
            })
        });
    });
});

.noData

Returns whether the cursor has reached the end of the result set. Fetch must be called at least once before noData can return true. Used for determining if there are no more results to retrieve from the cursor.

Parameters:

None

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function cursorExample() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    const cursor = await connection.query('SELECT * FROM MY_TABLE', { cursor: true, fetchSize: 3 });
    // As long as noData is false, keep calling fetch
    while (!cursor.noData)
    {
        const result = await cursor.fetch();
        // Now have a results array of size 3 (or less) that we can use
    }
    await cursor.close();
}

cursorExample();

Callbacks

const odbc = require('odbc');

odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.query('SELECT * FROM MY_TABLE', { cursor: true, fetchSize: 3 }, (error1, cursor) => {
        if (error1) { return; } // handle
        cursor.fetch((error2, results) => {
            if (error2) { return; } // handle
            // Now have a results array of size 3 (or less) that we can use
            if (!cursor.noData) {
                // Still more data to retrieve!
            } else {
                cursor.close((error3) => {
                    if (error3) { return; } // handle
                    // cursor now closed, now do more work
                });
            }
        });
    });
});

.close(callback?)

Closes the statement that the cursor was generated from, and by extension the cursor itself. Needs to be called when the cursor is no longer needed.

Parameters:

Examples:

Promises

const odbc = require('odbc');

// can only use await keyword in an async function
async function cursorExample() {
    const connection = await odbc.connect(`${process.env.CONNECTION_STRING}`);
    const cursor = await connection.query('SELECT * FROM MY_TABLE', { cursor: true, fetchSize: 3 });
    const result = await cursor.fetch();
    // Now have a results array of size 3 (or less) that we can use
    await cursor.close();
}

cursorExample();

Callbacks

const odbc = require('odbc');

odbc.connect(`${process.env.CONNECTION_STRING}`, (error, connection) => {
    connection.query('SELECT * FROM MY_TABLE', { cursor: true, fetchSize: 3 }, (error1, cursor) => {
        if (error1) { return; } // handle
        cursor.fetch((error2, results) => {
            if (error2) { return; } // handle
            // Now have a results array of size 3 (or less) that we can use
            cursor.close((error3) => {
                if (error3) { return; } // handle
                // cursor now closed, now do more work
            })
        });
    });
});


Future improvements

Development of node-odbc is an ongoing endeavor, and there are many planned improvements for the package. If you would like to see something, simply add it to the Issues and we will respond!

contributors

license

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies ofthe Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.