Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to use stored procedure as datasource (mySQL) #89

Open
ibexa-yuna opened this issue Jul 15, 2021 · 12 comments
Open

Unable to use stored procedure as datasource (mySQL) #89

ibexa-yuna opened this issue Jul 15, 2021 · 12 comments
Labels
bug Something isn't working

Comments

@ibexa-yuna
Copy link

Describe the bug

I have a very complex query that needs to be executed to gather data from multiple tables using many different IFs in a query with variables.

If I put CALL procedure_name as a query, and this stored procedure returns the data I need to have a metric I'm getting an error:

2021-07-15T13:22:32Z query-exporter.daemon[2117909]: (Background on this error at: http://sqlalche.me/e/13/f405)
2021-07-15T13:27:32Z query-exporter.daemon[2117909]: Error closing cursor
2021-07-15T13:27:32Z query-exporter.daemon[2117909]: Traceback (most recent call last):
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:   File "/snap/query-exporter/760/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 771, in _commit_impl
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:     self.engine.dialect.do_commit(self.connection)
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:   File "/snap/query-exporter/760/lib/python3.8/site-packages/sqlalchemy/dialects/mysql/base.py", line 2497, in do_commit
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:     dbapi_connection.commit()
2021-07-15T13:27:32Z query-exporter.daemon[2117909]: MySQLdb._exceptions.ProgrammingError: (2014, "Commands out of sync; you can't run this command now")
2021-07-15T13:27:32Z query-exporter.daemon[2117909]: The above exception was the direct cause of the following exception:
2021-07-15T13:27:32Z query-exporter.daemon[2117909]: Traceback (most recent call last):
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:   File "/snap/query-exporter/760/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1301, in _execute_context
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:     self._root._commit_impl(autocommit=True)
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:   File "/snap/query-exporter/760/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 773, in _commit_impl
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:     self._handle_dbapi_exception(e, None, None, None, None)
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:   File "/snap/query-exporter/760/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1510, in _handle_dbapi_exception
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:     util.raise_(
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:   File "/snap/query-exporter/760/lib/python3.8/site-packages/sqlalchemy/util/compat.py", line 182, in raise_
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:     raise exception
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:   File "/snap/query-exporter/760/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 771, in _commit_impl
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:     self.engine.dialect.do_commit(self.connection)
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:   File "/snap/query-exporter/760/lib/python3.8/site-packages/sqlalchemy/dialects/mysql/base.py", line 2497, in do_commit
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:     dbapi_connection.commit()
2021-07-15T13:27:32Z query-exporter.daemon[2117909]: sqlalchemy.exc.ProgrammingError: (MySQLdb._exceptions.ProgrammingError) (2014, "Commands out of sync; you can't run this command now")
2021-07-15T13:27:32Z query-exporter.daemon[2117909]: (Background on this error at: http://sqlalche.me/e/13/f405)
2021-07-15T13:27:32Z query-exporter.daemon[2117909]: During handling of the above exception, another exception occurred:
2021-07-15T13:27:32Z query-exporter.daemon[2117909]: Traceback (most recent call last):
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:   File "/snap/query-exporter/760/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1368, in _safe_close_cursor
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:     cursor.close()
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:   File "/snap/query-exporter/760/lib/python3.8/site-packages/MySQLdb/cursors.py", line 83, in close
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:     while self.nextset():
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:   File "/snap/query-exporter/760/lib/python3.8/site-packages/MySQLdb/cursors.py", line 137, in nextset
2021-07-15T13:27:32Z query-exporter.daemon[2117909]:     nr = db.next_result()
2021-07-15T13:27:32Z query-exporter.daemon[2117909]: MySQLdb._exceptions.OperationalError: (2006, "Commands out of sync; you can't run this command now")
2021-07-15T13:27:32Z query-exporter.daemon[2117909]: 2021-07-15 13:27:32,622 - ERROR - query-exporter - query "model_conseq_builds" on database "monitorDB" failed: (MySQLdb._exceptions.ProgrammingError) (2014, "Commands out of sync; you can't run this command now")
2021-07-15T13:27:32Z query-exporter.daemon[2117909]: (Background on this error at: http://sqlalche.me/e/13/f405)

Seems like SQLAlchemy doesn't want to recognize SP resultset as valid data.

Installation details

  • operating system: CentOS 8
  • query-exporter installation type:
    • snap:
name:      query-exporter
summary:   Export Prometheus metrics from SQL queries
publisher: Alberto Donato (ack)
store-url: https://snapcraft.io/query-exporter
contact:   https://github.com/albertodonato/query-exporter/issues
license:   GPL-3.0+
description: |
  query-exporter is a Prometheus exporter which allows collecting metrics from
  database queries, at specified time intervals or when a request to the
  metrics endpoint is performed.
  
  Each query can be run on multiple databases, and update multiple metrics.
  
  The snap provides both the `query-exporter` command and a deamon instance of
  the command, managed via a Systemd service.
  To run the latter:
  
    - create or edit `/var/snap/query-exporter/current/config.yaml` with the
      configuration
    - run `sudo snap restart query-exporter`
  
  Currently supported databases are:
  
    - PostgreSQL (`postgresql://`)
    - MySQL (`mysql://`)
    - SQLite (`sqlite://`)
    - Microsoft SQL Server (`mssql://`)
    - IBM DB2 (`db2://`) on supported architectures (x86_64, ppc64le and
      s390x)
commands:
  - query-exporter
services:
  query-exporter.daemon: simple, enabled, active
snap-id:      ssukadvQVTCbvJ0h7QH6ouseq7X9vbib
tracking:     latest/stable
refresh-date: 2021-03-28
channels:
  latest/stable:    2.7.0              2021-03-28 (760) 53MB -
  latest/candidate: ↑                                        
  latest/beta:      ↑                                        
  latest/edge:      2.7.0+git3.48e8900 2021-06-05 (771) 42MB -
installed:          2.7.0                         (760) 53MB -
@ibexa-yuna ibexa-yuna added the bug Something isn't working label Jul 15, 2021
@albertodonato
Copy link
Owner

Could you please paste your (sanitized as needed) query-exporter config?

@albertodonato
Copy link
Owner

Closing this as it's incomplete. Please reopen providing the required info.

@tworzenieweb
Copy link

This issue is real, for example this is my case:

databases:
  prod_tracking_db:
    dsn: env:CONNECTION_STRING_PROD_TRACKING_DB

metrics:
  link_clicks:
    type: gauge

queries:
  password_mail_tracking_query:
    interval: 5m
    databases: [prod_tracking_db]
    metrics: [mail_opens, link_clicks]
    sql: >
      CALL get_clicks_and_opens_for_mail_types("'id_14'", "1 day");
> call get_clicks_and_opens_for_mail_types("'id_14'", "5 MINUTE")

******************** 1. row *********************
link_opens: 1
mail_opens: 7
1 rows in set

@albertodonato
Copy link
Owner

Could you please provide an example of a store procedure that would return the expected data?

Doesn't have to be the real one, a simpler reproducer would be enough

@albertodonato albertodonato reopened this Feb 10, 2022
@tworzenieweb
Copy link

tworzenieweb commented Feb 10, 2022

Table for today's date:

CREATE TABLE `link_open_2022_02_10` (
  `id` char(36) NOT NULL,
  `link` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `mail_id` char(36) NOT NULL,
  `mail_type` varchar(255) DEFAULT NULL,
  `user_id` int NOT NULL,
  `user_agent` varchar(255) NOT NULL,
  `utm_source` varchar(255) DEFAULT NULL,
  `utm_content` varchar(255) DEFAULT NULL,
  `utm_campaign` varchar(255) DEFAULT NULL,
  `utm_medium` varchar(255) DEFAULT NULL,
  `opened_at` datetime NOT NULL,
  `data` json DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `INDEX_MAIL_LINK_ID` (`mail_id`),
  KEY `INDEX_MAIL_TYPE` (`mail_type`),
  KEY `INDEX_USER_ID` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `mail_open_2022_02_10` (
  `id` char(36) NOT NULL,
  `mail_id` char(36) NOT NULL,
  `mail_type` varchar(255) DEFAULT NULL,
  `user_id` int NOT NULL,
  `user_agent` varchar(255) NOT NULL,
  `opened_at` datetime NOT NULL,
  `data` json DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `INDEX_MAIL_ID` (`mail_id`),
  KEY `INDEX_MAIL_TYPE` (`mail_type`),
  KEY `INDEX_USER_ID` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE DEFINER=`dbuser`@`%` PROCEDURE `get_clicks_and_opens_for_mail_types`(
  IN type_id_list VARCHAR(255),
  IN timeframe VARCHAR(50)
)
BEGIN
SET @date := DATE_FORMAT(now(), "%Y_%m_%d");
SET @link_open_table := CONCAT('link_open_', @date);
SET @mail_open_table := CONCAT('mail_open_', @date);

SET @query := CONCAT('SELECT (SELECT COUNT(distinct user_id) FROM ', @link_open_table, ' WHERE opened_at > now() - INTERVAL ', timeframe ,' AND mail_type IN (', type_id_list, ')) as link_opens, (SELECT COUNT(distinct user_id) FROM ', @mail_open_table, ' WHERE opened_at > now() - interval ', timeframe , ' AND mail_type IN (', type_id_list, ')) as mail_opens;');
PREPARE stmt FROM @query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END

@albertodonato
Copy link
Owner

What version of mysql are you using?

I'm trying to create a similar stored procedure but I get the following error:

mysql> CREATE PROCEDURE myproc( IN a INT, IN b INT) BEGIN SET @query := CONCAT('SELECT * FROM t WHERE x > ', a, ' AND x < ', b, ';'); PREPARE stmt FROM @query; EXECUTE stmt; DEALLOCATE PREPARE stmt; END;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1
ERROR 1243 (HY000): Unknown prepared statement handler (stmt) given to EXECUTE
ERROR 1243 (HY000): Unknown prepared statement handler (stmt) given to DEALLOCATE PREPARE
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'END' at line 1

Also, to return data from the procedure, don't you need to define an OUT parameter in which result gets stored?

@tworzenieweb
Copy link

tworzenieweb commented Feb 18, 2022

DB Version:

percona 8.0.26-17 so MySQL 8

I am calling it that way:

call get_clicks_and_opens_for_mail_types("'id_14'", "5 MINUTE");

Getting the results outputted directly without assigning it to any custom variable - it's like a regular select returning rows

Execute:
> call get_clicks_and_opens_for_mail_types("'id_14'", "5 MINUTE")

+ --------------- + --------------- +
| link_opens      | mail_opens      |
+ --------------- + --------------- +
| 0               | 1               |
+ --------------- + --------------- +
1 rows

@tworzenieweb
Copy link

@albertodonato any progress on this? is there any chance to have a fix?

@lchopfpt
Copy link

I am having a similar issue with Percona 5.7.26. Trying to use query_exporter to pass table or columns as parameters doesn't work, so created a procedure to do it for me.

Procedure definition:
DELIMITER // CREATE PROCEDURE mysql.min_max_ts ( IN db_name nvarchar(25), IN tab_name CHAR(16), IN col VARCHAR(100), IN min_max char(3) ) BEGIN SET @s = CONCAT( 'SELECT unix_timestamp(', min_max, '(', col, ')) as ', min_max, '_ts FROM ', db_name, '.' , tab_name ); PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt; END // DELIMITER ;
Then to call it:
mysql.min_max_ts('<database>', '<table>', 'created', 'min');

ERROR:
2022-12-28 23:50:13,398 - ERROR - query-exporter - query "min_ts" on database "<dbname>" failed: (MySQLdb.ProgrammingError) (2014, "Commands out of sync; you can't run this command now")

@rradutzu
Copy link

Any update on the above? I am also getting the same error when trying to use a stored procedure as a data source. Surely this should be possible, as you might want to have complex logic when querying data, which is not achievable with standard query functionality.

@lchopfpt
Copy link

lchopfpt commented Jan 17, 2023

I have tried drastically simplifying just to see if I can find when a stored proc will work.
I tried no in/out parameters with a single select, so at its most basic was a simple as possible. And we still get the "commands out of sync".

Some google searches suggest that maybe it's about closing cursors and reading the resultset.

@lchopfpt
Copy link

Found this on the googles.
This is a documented behavior of MySQLdb:
Compatibility note: It appears that the mere act of executing the CALL statement produces an empty result set, which appears after any result sets which might be generated by the stored procedure. Thus, you will always need to use nextset() to advance result sets.
Might also have to close cursors.
https://stackoverflow.com/questions/11583083/python-mysql-commands-out-of-sync-you-cant-run-this-command-now
https://dev.mysql.com/doc/refman/8.0/en/commands-out-of-sync.html
https://code.djangoproject.com/ticket/17289

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants