IBM / nodejs-idb-connector

A JavaScript (Node.js) library for communicating with Db2 for IBM i, with support for queries, procedures, and much more. Uses traditional callback-style syntax
MIT License
38 stars 23 forks source link

Character conversion between CCSID 1208 and CCSID 65535 not valid. #134

Closed edmundpf closed 3 years ago

edmundpf commented 3 years ago

Node.js version: v12.16.1 idb-connector version: idb-connector@1.2.9 IBM i version: 3 7

    async query(sql: string, params: Array<any> = [], isSelect = true) {
        this.statement = new dbstmt(this.connection)
        const result: SqlQueryResult = {
            data: [],
            metadata: {},
        }
        return new Promise<SqlQueryResult>((resolve, reject) => {
            this.statement.prepare(sql, (err) => {
                if (err) {
                    return reject(err)
                }
                this.statement.bindParameters(params, (err) => {
                    if (err) {
                        return reject(err)
                    }
                    this.statement.execute((out, err) => {
                        if (err) {
                            return reject(err)
                        }
                        if (!isSelect) {
                            return resolve(out)
                        } else {
                            this.statement.fetchAll((res) => {
                                result.data = res
                                return resolve(result)
                            })
                        }
                    })
                })
            })
        })
            .then((res) => {
                this.statement.close()
                return res
            })
            .catch((err) => {
                this.statement.close()
                return {
                    ...result,
                    error: serializeError(err),
                }
            })
    }

const main = async () => {
    await db.query(
    'UPDATE qs36f.repTimeT SET modified = CURRENT TIMESTAMP, filename = ?, time = ? WHERE id = ? WITH NONE',
    [ 'REPORT AS OF 01-28-2021.PDF', '2021-01-28 19:00:01.000', 'WHCONS' ],
    false
}

await main()
BindParameters().
SQLBindParameter(0) TYPE[12] SIZE[ 50] DIGI[0] IO[3] IND[ 27] INDEX[0]
SQLBindParameter(0) TYPE[93] SIZE[ 26] DIGI[6] IO[3] IND[ 23] INDEX[1]
SQLBindParameter(0) TYPE[12] SIZE[ 30] DIGI[0] IO[3] IND[  6] INDEX[2]
Execute().
SQLExecuteAsync(-1):
SQLFreeStmt: stmth 3 [SQL_DROP]
SQLFreeStmt(0)

UPDATE qs36f.repTimeT
SET
    modified = CURRENT TIMESTAMP,
    filename = ?,
    time = ?
     WHERE
        id = ?
WITH NONE
 [ 'REPORT AS OF 01-28-2021.PDF', '2021-01-28 19:00:01.000', 'WHCONS' ]

I can insert timestamps into a table, but when attempting to simply update the timestamp using a parameterized query, you'll see I'm trying to update with the time = ? clause, this always causes a SQL Error as follows:

error: {
      name: 'Error',
      message: 'SQLSTATE=57017 SQLCODE=-332 Character conversion between CCSID 1208 and CCSID 65535 not valid.',
      stack: 'Error: SQLSTATE=57017 SQLCODE=-332 Character conversion between CCSID 1208 and CCSID 65535 not valid.'
    }

If I simply substitute in the timestamp as a string without the parameterized '?' operator, such as time = '2021-01-28 19:00:01.000' the update works fine. Note that trying to insert this value with a parameterized '?' works as well. If I look at the table CCSID via IBMi via DSPFD command in IBMi, it is listed as 37. The fields also are listed as 37 when I use the DSPFFD command. I have tried setting the CCSID environment variable to '0', '37', '1208', and '65535', all with no luck, some returning no records in selects, some erroring out, some not allowing a connection whatsoever.

To Reproduce Steps to reproduce the behavior:

  1. Try to update a timestamp field with a properly formatted timestamp string using a parameterized query and bound parameters
  2. Error is thrown

Expected behavior An update with a date string should go through with no issues.

abmusse commented 3 years ago

I have tried setting the CCSID environment variable to '0', '37', '1208', and '65535'

Try updating the CCSID for your User profile with the following CL command.

CHGUSRPRF USRPRF(USER) CCSID(CCSID)

CCSID 37 is valid for United States other English speaking countries

It is possible that your user profile CCSID is currently set to *SYSVAL and the system value is set to 65535.

View the system value with:

WRKSYSVAL SYSVAL(QCCSID)
edmundpf commented 3 years ago

I have tried setting the CCSID environment variable to '0', '37', '1208', and '65535'

Try updating the CCSID for your User profile with the following CL command.

CHGUSRPRF USRPRF(USER) CCSID(CCSID)

CCSID 37 is valid for United States other English speaking countries

It is possible that your user profile CCSID is currently set to *SYSVAL and the system value is set to 65535.

View the system value with:

WRKSYSVAL SYSVAL(QCCSID)

Thank you I will try this and let you know if this resolves the issue ASAP

edmundpf commented 3 years ago

I have tried setting the CCSID environment variable to '0', '37', '1208', and '65535'

Try updating the CCSID for your User profile with the following CL command.

CHGUSRPRF USRPRF(USER) CCSID(CCSID)

CCSID 37 is valid for United States other English speaking countries It is possible that your user profile CCSID is currently set to *SYSVAL and the system value is set to 65535. View the system value with:

WRKSYSVAL SYSVAL(QCCSID)

Thank you I will try this and let you know if this resolves the issue ASAP

This worked, keep in mind for others facing this issue, after you CHGUSRPRF for the user, you may have to log out of shell and back in or restart whatever process uses this for the change to take. Will go ahead and close.

abmusse commented 3 years ago

Glad you got this resolved! This is a common issue can read more about why here: http://yips.idevcloud.com/wiki/index.php/IBMi/65535.

kadler commented 3 years ago

Another option might be to set the SQL_ATTR_NON_HEXCCSID CLI environment attribute. This will change the job CCSID to the default job CCSID if the the job CCSID is 65535. The default job CCSID is guaranteed to be a non-65535 CCSID.

Although idb-connector supports setting attributes, I'm not sure if this one can be set by the user, since it's an environment attribute and thus require a code change in idb-connector. FWIW, in the version of Python ibm_db we ship, we force this on: https://github.com/kadler/python-ibmdb/blob/ibmi/IBM_DB/ibm_db/ibm_db.c#L1492

abmusse commented 3 years ago

Nice! I think we should do the same in this package given that the CCSID 1208 and CCSID 65535 not valid issue is quite common.

kadler commented 3 years ago

Agreed!