2011-09-02 16 views
5

Tengo una tabla llamada sales_observation_daily_summary que es una vista materializada de sales_observation_daily_summary_view. He definido un procedimiento almacenado llamado sync_daily_summary_view_with_table que refrescará la vista materializada. Funcionalmente, funciona exactamente como esperaba. Sin embargo, tengo un error extraño al llamar el procedimiento almacenado dos veces en la misma conexión (un escenario probable cuando se utiliza un grupo de conexiones). Originalmente esto surgió en mis pruebas de integración de Java, pero puedo reproducirlo fácilmente en MySQL Workbench, por lo que no debería tener nada que ver con JDBC o Spring ni nada de este tipo.El procedimiento almacenado MySQL falla en la segunda llamada en la misma conexión con "SELECCIONAR comando denegado al usuario 'usuario' @ 'localhost' para la tabla 'nombre_vista'

call sync_daily_summary_view_with_table(); 
call sync_daily_summary_view_with_table(); 

En la primera llamada, hace lo que se supone que debe hacer y lo devuelve normalmente. En la segunda llamada, me sale:

Error Code: 1142 
SELECT command denied to user 'test'@'localhost' for table 'one_pg_someone_sales_observation_daily_summary_view' 

one_pg_someone_sales_observation_daily_summary_view se hace referencia en sales_observation_daily_summary_view, que se cita en el procedimiento almacenado. El mensaje de error no tiene sentido ya que, en primer lugar, el procedimiento almacenado no se objetó la primera vez que se ejecutó y, en segundo lugar, ese usuario tiene muchos derechos para seleccionar en esa vista.

No voy a mostrar todas las vistas involucrado ya que es muy complejo pero el sales_observation_daily_summary_view se define como una unión de varios otros puntos de vista así:

CREATE ALGORITHM=UNDEFINED DEFINER=`test`@`localhost` 
SQL SECURITY DEFINER 
VIEW `sales_observation_daily_summary_view` AS 
     /* Specific Stage and Observer */ 
     SELECT zone, 
       session_date, 
       session_year, 
       session_month, 
       session_week, 
       phenomenon_group_id, 
       phenomenon_group_name, 
       stage_id, 
       stage_name, 
       observer_id, 
       series_name, 
       benchmark_id, 
       session_count, 
       session_value, 
       benchmark_value 
     FROM one_pg_someone_sales_observation_daily_summary_view 
     UNION ALL /* All Stages */ 
     SELECT zone, 
       session_date, 
       session_year, 
       session_month, 
       session_week, 
       phenomenon_group_id, 
       phenomenon_group_name, 
       stage_id, 
       stage_name, 
       observer_id, 
       series_name, 
       benchmark_id, 
       session_count, 
       session_value, 
       benchmark_value 
     FROM all_stages_someone_sales_observation_daily_summary_view 
     UNION ALL /* All Activities */ 
     SELECT zone, 
       session_date, 
       session_year, 
       session_month, 
       session_week, 
       phenomenon_group_id, 
       phenomenon_group_name, 
       stage_id, 
       stage_name, 
       observer_id, 
       series_name, 
       benchmark_id, 
       session_count, 
       session_value, 
       benchmark_value 
     FROM all_activities_someone_sales_observation_daily_summary_view 
     UNION ALL /* All Observers */ 
     SELECT zone, 
       session_date, 
       session_year, 
       session_month, 
       session_week, 
       phenomenon_group_id, 
       phenomenon_group_name, 
       stage_id, 
       stage_name, 
       observer_id, 
       series_name, 
       benchmark_id, 
       session_count, 
       session_value, 
       benchmark_value 
     FROM one_pg_everyone_sales_observation_daily_summary_view 
     UNION ALL /* Everyone over All Stages */ 
     SELECT zone, 
       session_date, 
       session_year, 
       session_month, 
       session_week, 
       phenomenon_group_id, 
       phenomenon_group_name, 
       stage_id, 
       stage_name, 
       observer_id, 
       series_name, 
       benchmark_id, 
       session_count, 
       session_value, 
       benchmark_value 
     FROM all_stages_everyone_sales_observation_daily_summary_view 
     UNION ALL /* Everyone over All Activities */ 
     SELECT zone, 
       session_date, 
       session_year, 
       session_month, 
       session_week, 
       phenomenon_group_id, 
       phenomenon_group_name, 
       stage_id, 
       stage_name, 
       observer_id, 
       series_name, 
       benchmark_id, 
       session_count, 
       session_value, 
       benchmark_value 
     FROM all_activities_everyone_sales_observation_daily_summary_view 
     UNION ALL /* Benchmark */ 
     SELECT zone, 
       session_date, 
       session_year, 
       session_month, 
       session_week, 
       phenomenon_group_id, 
       phenomenon_group_name, 
       stage_id, 
       stage_name, 
       observer_id, 
       series_name, 
       benchmark_id, 
       session_count, 
       session_value, 
       benchmark_value 
     FROM benchmark_sales_observation_daily_summary_view 

El procedimiento almacenado se define así:

DELIMITER $$ 

CREATE DEFINER=`test`@`localhost` PROCEDURE `sync_daily_summary_view_with_table`() 
BEGIN 

       /* Update any values that may have changed */ 
       UPDATE sales_observation_daily_summary tb, 
         sales_observation_daily_summary_view vw 
       SET tb.session_count = vw.session_count, 
         tb.session_value = vw.session_count, 
         tb.benchmark_value = vw.benchmark_value, 
         tb.series_name = vw.series_name 
       WHERE vw.zone = tb.zone 
         AND vw.session_date = tb.session_date 
         AND Coalesce(vw.phenomenon_group_id, 0) = 
          Coalesce(tb.phenomenon_group_id, 0) 
         AND Coalesce(vw.stage_id, 0) = Coalesce(tb.stage_id, 0) 
         AND Coalesce(vw.observer_id, 0) = Coalesce(tb.observer_id, 0) 
         AND Coalesce(vw.benchmark_id, 0) = Coalesce(tb.benchmark_id, 0) 
         AND (Coalesce(tb.session_count, -1) <> Coalesce(vw.session_count, -1) 
           OR Coalesce(tb.session_value, -1) <> 
           Coalesce(vw.session_value, -1) 
           OR Coalesce(tb.benchmark_value, -1) <> 
           Coalesce(vw.benchmark_value, -1) 
           OR tb.series_name <> vw.series_name); 
END 

Estoy usando la versión 5.1.56-log en mi caja de desarrollo local.
ACTUALIZACIÓN 1 También he reproducido el error en un servidor de Amazon RDS versión 5.1.57-log.

ACTUALIZACIÓN 2 Si defino el procedimiento almacenado para ser SQL SECURITY INVOKER y ejecutarlo como root, que funciona bien. Esta no es una solución aceptable, pero podría ser algún tipo de pista. (Por ejemplo, no es un problema de bloqueo de tabla.

ACTUALIZACIÓN 3 Las tablas involucradas son las tablas InnoDB. No estoy seguro de si se trata de una pista, pero cuando he añadido un inicio de transacción al principio y un COMMIT al al final, se tomó mucho más tiempo para completar, pero luego consiguió el mismo error en el segundo invocación.

ACTUALIZACIÓN 4 he simplificado el procedimiento almacenado y siendo reproducido el problema. se solía tener una instrucción de inserción seguido por una declaración de actualización. Resulta que la declaración de actualización es suficiente para reproducir el error, por lo que eliminé la instrucción de inserción del procedimiento almacenado ab ove

+0

¿Se puede reproducir en otro servidor? – Devart

+0

Sí, he editado mi descripción para reflejar eso. Tanto 5.1.56 en mi cuadro local como 5.1.57 en Amazon RDS tienen este problema. – jhericks

+0

¿Eres el único que usa las vistas/el procedimiento almacenado? Parece que una de las tablas en la (s) vista (s) podría estar bloqueada. – Mindfulgeek

Respuesta

0

Esto puede ser un problema de transacción. Intente agregar un COMMIT después de las instrucciones UPDATE e INSERT. También puede intentar usar InnoDB si aún no lo está.

Usted debe tratar de la función como esta para ver si se obtiene el mismo resultado:

DELIMITER $$ 

CREATE DEFINER=`test`@`localhost` PROCEDURE `sync_daily_summary_view_with_table`() 
BEGIN 

      /* Update any values that may have changed */ 
      UPDATE sales_observation_daily_summary tb, 
        sales_observation_daily_summary_view vw 
      SET tb.session_count = vw.session_count, 
        tb.session_value = vw.session_count, 
        tb.benchmark_value = vw.benchmark_value, 
        tb.series_name = vw.series_name 
      WHERE vw.zone = tb.zone 
        AND vw.session_date = tb.session_date 
        AND Coalesce(vw.phenomenon_group_id, 0) = 
         Coalesce(tb.phenomenon_group_id, 0) 
        AND Coalesce(vw.stage_id, 0) = Coalesce(tb.stage_id, 0) 
        AND Coalesce(vw.observer_id, 0) = Coalesce(tb.observer_id, 0) 
        AND Coalesce(vw.benchmark_id, 0) = Coalesce(tb.benchmark_id, 0) 
        AND (Coalesce(tb.session_count, -1) <> Coalesce(vw.session_count, -1) 
          OR Coalesce(tb.session_value, -1) <> 
          Coalesce(vw.session_value, -1) 
          OR Coalesce(tb.benchmark_value, -1) <> 
          Coalesce(vw.benchmark_value, -1) 
          OR tb.series_name <> vw.series_name); 
      COMMIT; 
END 
+0

Estas son tablas InnoDB. No estoy seguro de si es una pista, pero cuando agregué una Transacción de inicio al principio y un Compromiso al final, pareció colgarse. Simplemente corrió, corrió, y nunca volvió. – jhericks

+0

Corrección, no se colgó, solo tardó mucho más en ejecutarse. Sin embargo, obtuve el mismo error en la segunda ejecución. – jhericks

+0

Si tarda mucho más tiempo en ejecutarse, me hace pensar que la función está actualizando un gran número de filas. – Hunter

2

¿Cuál es el valor de confirmación automática? select @@ autocommit;

Si el valor es 0 intente agregar una confirmación entre las dos llamadas ya que podría tener una transacción abierta de alguna manera llamada sync_daily_summary_view_with_table(); commit; llamada sync_daily_summary_view_with_table();

¿La tabla materializada forma parte de alguna de las vistas?

+0

autocommit es '1'. La tabla aún no forma parte de ninguna vista, aunque mi plan era crear algunas vistas con filtros muy simples en la columna 'zone'. – jhericks

0

esto parece que podría ser un problema de permitir que varias instrucciones en una consulta

esto (http://dev.mysql.com/doc/refman/5.0/en/mysql-set-server-option.html) podría ser una opción:

mysql_set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_ON) 

o mejor durante la conexión:

mysql_real_connect (
    mysql, 
    host_name, 
    user_name, 
    password, 
    db_name, 
    port_num, 
    socket_name, 
    CLIENT_MULTI_STATEMENTS) 

también debería echar un vistazo aquí para una mejor explicación: http://dev.mysql.com/doc/refman/5.0/en/c-api-multiple-queries.html

+0

Este no es el problema. A través de MySQL Workbench ejecuto regularmente múltiples declaraciones separadas por ';' y puedo reproducir el problema en Workbench. Además, no es necesario que haga 'call sync_daily_summary_view_with_table(); llama a sync_daily_summary_view_with_table(); 'de una vez. También puedo reproducir el problema ejecutando 'call sync_daily_summary_view_with_table()' una vez, esperando a que se complete y luego ejecutarlo de nuevo en la misma conexión. Solo funciona una vez por conexión, no una vez por solicitud. – jhericks

0

No sé si ustedes han encontrado una solución para este problema. ¡Me encontré con lo mismo y pude arreglarlo!

El problema que tengo simplemente sucede cuando intento hacer una selección en una vista a través de un procedimiento. Ar primera vez simplemente funcionó bien, pero desde la segunda vez estaba respondiendo un mensaje de comando denegado para mi usuario.

La solución fue crear la vista con un usuario "administrador", hacer lo mismo con el procedimiento (crearlo con un usuario "administrador"), ¡con esos procesos lo ejecuté!

El problema es que no sé exactamente cómo, MySQL utiliza a otro usuario para hacer la selección a través de la vista, no usa el definidor o el usuario de sesión registrado, y en el segundo momento, este "interno" el usuario recibe denegado de vista.

¡Espero poder ayudarlos a resolver este problema!

Cuestiones relacionadas