Search code examples
node.jsoraclenode-oracledb

NodeJS ,Partial binding of Oracle DB parameters gives : ORA-01036


I'm working on a task that has some insert/update on some table.

when I use the full columns of the table in the insert/update statements it works for me but whenever I'm only updating the required columns and neglect the remaining to be untouched I face the ORA-01036

I'm calling a generic Lambda function passing the query and parameters Success scenario :

{ "stage": "dev", "params": { "id": 5956049, "groupName": "testtoberemoved123", "externalName": "Axiom_420K_Wheattest547", "description": "desc 123", "createdOn": "2018-08-27T22:00:00.000Z", "createdBy": "EOM", "updatedOn": "2018-08-28T16:16:41.207Z", "updatedBy": "EOM", "status": 1, "vendorID": null, "technologyCode": null }, "query": "update assay_group set NAME=:groupName , EXTERNAL_NAME=:externalName, DESCRIPTION=:description ,CREATED_DATE=to_timestamp_tz( :createdOn, 'yyyy-mm-dd"T"hh24:mi:ss:ff3 TZH:TZM'),CREATED_USER=:createdBy ,LAST_UPDATED_DATE=to_timestamp_tz( :updatedOn, 'yyyy-mm-dd"T"hh24:mi:ss:ff3 TZH:TZM'),LAST_UPDATED_USER=:updatedBy ,GROUP_STATUS=:status,VENDOR_ID=:vendorID,TECHNOLOGY_CODE=:technologyCode where ID=:id", "enableObjectFormat": true, "options": { "autoCommit": true } }

this one runs successfully , but just when removing some columns from the statement it fails as below scenario :

{ "stage": "dev", "params": { "id": 5956049, "groupName": "testtoberemoved123", "externalName": "Axiom_420K_Wheattest547", "description": "desc 123", "createdOn": "2018-08-27T22:00:00.000Z", "createdBy": "EOM", "updatedOn": "2018-08-28T16:09:36.215Z", "updatedBy": "EOM", "status": 3, "vendorID": null, "technologyCode": null }, "query": "update assay_group set NAME=:groupName where ID=:id", "enableObjectFormat": true, "options": { "autoCommit": true } }

and this results in the following error : {"errorMessage":"Error while executing query - ORA-01036: illegal variable name/number\n",

Generic executor as below

`

'use strict';

var oracledb =  require("oracledb-for-lambda");
var dbConfig = require('./resources/dbConfig-dev.js');

module.exports.executeQuery= (event, context, callback) => {

  var maxSize = parseInt(process.env.maxRows, 10);

  // Extract enableJSONParse option
  var enableJSONParse = false;
  if(event.enableJSONParse != null && event.enableJSONParse != undefined) {
    enableJSONParse = event.enableJSONParse;
    console.log("enableJSONParse provided in event");
  }
  console.log("Enable JSON Parse: " + enableJSONParse);

  // Extract options 
  var options = {};
  if(event.options != null && event.options != undefined) {
    options = event.options;
    console.log("options provided in event");
  }
  // Add maxSize to options
  options.maxRows = maxSize;
  console.log("Options: " + JSON.stringify(options));

  // Set oracledb output format to object
  var enableObjectFormat = event.enableObjectFormat;
  console.log("Enable Object Format: " + enableObjectFormat);
  if(enableObjectFormat) {
    console.log("Object Format Enabled");
    oracledb.outFormat = oracledb.OBJECT;
  } else {
    oracledb.outFormat = oracledb.ARRAY;
  }
  console.log("oracledb.outFormat: " + oracledb.outFormat);

  var currentStage = event.stage;
  console.log("Current Stage: " + currentStage);

  if (currentStage != null && currentStage != 'undefined') {
      var configFileName = './resources/dbConfig-' + currentStage + '.js'  
    try{
      dbConfig = require(configFileName);
    } catch (error) {
      callback(new InternalServerError("No dbConfig found - " + error.message));
      return;
    }
  }
  console.log("Using dbConfig: " + JSON.stringify(dbConfig));

  var response = "";
  var parameters = event.params;
  var query =   event.query;

  if(query == null || query == undefined || query == "") { // Empty Query - throw error
    console.log("Missing required field - query")
    callback(new MissingRequiredFieldError("Missing Required Field - query"));
    return;
  }

  if(parameters == null || parameters == undefined) { // parameters not provided in event - set to empty list
    console.log("No parameters defined");
    parameters = [];
  }
  console.log("Query: " + query);
  console.log("Query Parameters: " + parameters);

    oracledb.getConnection(
  {
    user          : dbConfig.user,
    password      : dbConfig.password,
    connectString  :dbConfig.connectString
  },
  function(err, connection) {
    if (err) {
      console.error("Connection Error: " + err.message);
      callback(new InternalServerError("Error while connecting to database - "+ err.message));
      return;
    }
     // return all CLOBs as Strings
    oracledb.fetchAsString = [ oracledb.CLOB ];

    connection.execute(
      // The statement to execute
      query, 
      parameters,     // Query Param
      options, // Options
      // The callback function handles the SQL execution results
      function(err, result) {
        if (err) {
          console.error("Execution Error Messages = " + err.message);
          doRelease(connection);
          callback(new InternalServerError("Error while executing query - "+ err.message));
          return;          
        }
        console.log("Query " + query + " Executed Successfully");

        var resultSet;
        // In case query is SELECT
        if(result.rows != null && result.rows != undefined) {
          console.log("Returned rows: " + result.rows.length);
          console.log("Result.metaData: " + JSON.stringify(result.metaData)); 
          console.log("Result.rows: " + JSON.stringify(result.rows));           
          resultSet = result.rows;    
          try {        
            if(result.rows.length != undefined && result.rows.length == 0) {
              resultSet = [];
            } else if(enableJSONParse) {
              if(result.rows[0][0].type == oracledb.CLOB) {
                console.log("rows.type  is CLOB");
                resultSet = JSON.parse(result.rows[0][0]);
              }
              resultSet = JSON.parse(result.rows);
            }          

          } catch(error) {
            callback(new InternalServerError("Error while parsing result of query: "+error.message));
            return;
          }
        } else { // In case query is INSERT/UPDATE/DELETE        
          console.log("Result.rowsAffected: " + result.rowsAffected);
          if(result.rowsAffected > 0) {
            resultSet = 'Executed Succesfully - Rows Affected: '+ result.rowsAffected;
          } else {
            resultSet = 'No rows affected';
          }
        }
        doRelease(connection);
        callback(null, resultSet);                        
      });
  });

    // Note: connections should always be released when not needed
    function doRelease(connection) {
      connection.close(
        function(err) {
          if (err) {
              console.error(err.message);
              callback(new InternalServerError(err.message));
        return;
          }
        });
  }
};

`


Solution

  • The problem is that you are asking Oracle to set values for bind parameters that don't exist.

    Let's consider your statement update assay_group set NAME=:groupName where ID=:id. Oracle will parse this and then run through your bind parameters. It will set values for groupName and id fine, and then it will get to the parameter named externalName. However, there is no bind parameter :externalName in your statement.

    What's Oracle supposed to do with the value you've given to this non-existent parameter? You seem to be expecting Oracle to just ignore it. However, ignoring it isn't an option: if for example someone mistypes a parameter name this should in my opinion generate an error straight away rather than waiting until all the other parameters have been set and then complaining that one of them was missing.

    You will have to pass to your executeQuery function the parameters that are used by the query or statement being executed and no others.