mysqljs / mysql

A pure node.js JavaScript Client implementing the MySQL protocol.
MIT License
18.29k stars 2.52k forks source link

Not meeting a foreign key constraint causes error, callback not beeing called #1864

Closed marcesengel closed 6 years ago

marcesengel commented 6 years ago

Hi, I'm currently trying to do an INSERT which conflicts with my foreign key constraints and to detect if that's the case. Sadly, the callback I'm passing to query is not beeing called. Here's my code:

const query = (query, args = []) => new Promise((resolve, reject => {
  connection.query(query, args, (error, results, fields) => {
    this._releaseConnection(connection)

    if(error) {
      console.log('AN ERROR OCCURED!!!')
      reject(error)
    } else {
      resolve({ results, fields })
    }
  })
})

I'm expecting to have an AN ERROR OCCURED!!! printed to my console and to be able to catch the rejected Promise. However I'm only getting an extended log of the error (with callstack) and the callback is not beeing called. Here's the log:


    ER_NO_REFERENCED_ROW_2: Cannot add or update a child row: a foreign key constraint fails (`test`.`xxx`, CONSTRAINT `xxx_ibfk_1` FOREIGN KEY (`yyy`) REFERENCES `zzz` (`aaa`) ON DELETE CASCADE ON UPDATE CASCADE)

      at Query.Sequence._packetToError (node_modules/mysql/lib/protocol/sequences/Sequence.js:52:14)
      at Query.ErrorPacket (node_modules/mysql/lib/protocol/sequences/Query.js:77:18)
      at Protocol._parsePacket (node_modules/mysql/lib/protocol/Protocol.js:279:23)
      at Parser.write (node_modules/mysql/lib/protocol/Parser.js:76:12)
      at Protocol.write (node_modules/mysql/lib/protocol/Protocol.js:39:16)
      at Socket.<anonymous> (node_modules/mysql/lib/Connection.js:103:28)
          --------------------
      at Protocol._enqueue (node_modules/mysql/lib/protocol/Protocol.js:145:48)
      at PoolConnection.query (node_modules/mysql/lib/Connection.js:208:25)
      at _getConnection.then (src/shared/mysql/adapter.js:94:42)

Is this a fault on my end?

Thanks in advance for any help, DragonRaider5

dougwilson commented 6 years ago

Very strange. Where in your code are you printing that error out to the console? I don't see that in the code snipplet you provided. That may help track down what is happening. Just taking the code snippet you provided is working fine for me on Node.js 6.12.0.

dougwilson commented 6 years ago

I did change this._releaseConnection(connection) to connection.release() in my version, because I have no idea that this is and what that function does since it wasn't provided and wrapped it in a pool.getConnection as well. May help if you can provide complete code I can run without altering in case that is why I'm not able to reproduce since I have to make a lot of assumptions just to get the code to run at all.

marcesengel commented 6 years ago

Hi, I'm sorry for not providing everything. The this._releaseConnection() simply is a wrapper for connection.release(), like this:

_releaseConnection(connection) {
  connection.release()
}

Besides that, the this context belongs to my wrapper class (hexagonal architecture, hiding implementation/lib details from my main code).

I am printing out the error nowhere, that's what confused me and what my problem is ^^ it seems to get printed somewhere in mysqljs, as my callback is not beeing called (otherwise the console.log('AN ERROR OCCURED!!!') should be printed). I am calling my query function like this:

const query = (connection, query, args = []) => new Promise((resolve, reject => {
  connection.query(query, args, (error, results, fields) => {
    connection.release()

    if(error) {
      console.log('AN ERROR OCCURED!!!')
      reject(error)
    } else {
      resolve({ results, fields })
    }
  })
})

const getConnection = (pool) => new Promise((resolve, reject) => {
  pool.getConnection((error, connection) => error
    ? reject(error)
    : resolve(connection)
  ))
}

const reproduceTheError = async () => {
  const pool // init a connection pool
  const connection = await getConnection(pool)

  const result = await query(connection, 'SOME INSERT STATEMENT NOT MEETING A FOREIGN KEY CONSTRAINT')
    .catch((error) => console.error('An error occured', error.msg))
}

I'd expect to have both "An error occured" and "AN ERROR OCCURED!!!" printed out, but I'm only getting the callstack and error. That's why I can't react to the error (I need to catch it, as I rely on knowing wether or not the insert was successful), as my callback isn't getting called :/

Also I'm on Node v.8.9.0 inside a Docker container.

Does this help? Thanks for your quick response and patience!

dougwilson commented 6 years ago

Unfortunately it doesn't help :( There is no where in this module that would print the error (unless you can point out where to me) and running that on Node.js 8.9.0 does call the callback for me. Maybe we should get a sync on the exact steps such that we are running the exact same things. Can you provide all the following, please?

  1. Version of this module
  2. Version of your Mysql server
  3. Complete code that I can just copy and paste into a file and run without modification.
  4. Some DDL and data to setup my database in order to get the exact error you're getting.
  5. Complete instructions on how to get it all setup and running to see the issue you are describing.

Thanks!

kai-koch commented 6 years ago

"at _getConnection.then (src/shared/mysql/adapter.js:94:42)" This does not seem to be a part of mysqljs. If this is your wrapper could it be, that it does not catch the mysql-error correctly and simply throws it instead of pipeing it through to your callback?

marcesengel commented 6 years ago

Hi, thanks to all of you! I actually just did a VERY stupid mistake, so stupid, that I didn't find it... I've made my changes to the wrong function ^^

The problem appeared in my integration tests and for some reason I kept editing the wrong function (the one that passed the test), so that's why I didn't see any results.

I'm sorry for waisting your time - I appreciate your afford very much. Lesson learned 😭