OSDN Git Service

Fixed a crash bug by DECLARE CURSOR and enable_hint_table = on
[pghintplan/pg_hint_plan.git] / pg_hint_plan.c
index d4bbddd..fa83f2b 100644 (file)
@@ -1659,8 +1659,9 @@ get_hints_from_table(const char *client_query, const char *client_application)
 /*
  * Get client-supplied query string. Addtion to that the jumbled query is
  * supplied if the caller requested. From the restriction of JumbleQuery, some
- * kind of query needs special amendments. Reutrns NULL if the current hint
- * string is still valid.
+ * kind of query needs special amendments. Reutrns NULL if this query doesn't
+ * change the current hint. This function returns NULL also when something
+ * wrong has happend and let the caller continue using the current hints.
  */
 static const char *
 get_query_string(ParseState *pstate, Query *query, Query **jumblequery)
@@ -1670,15 +1671,22 @@ get_query_string(ParseState *pstate, Query *query, Query **jumblequery)
        if (jumblequery != NULL)
                *jumblequery = query;
 
-       if (query->commandType == CMD_UTILITY)
+       /* Query for DeclareCursorStmt is CMD_SELECT and has query->utilityStmt */
+       if (query->commandType == CMD_UTILITY || query->utilityStmt)
        {
                Query *target_query = query;
 
-               /* Use the target query if EXPLAIN */
-               if (IsA(query->utilityStmt, ExplainStmt))
+               /*
+                * Some utility statements have a subquery that we can hint on.  Since
+                * EXPLAIN can be placed before other kind of utility statements and
+                * EXECUTE can be contained other kind of utility statements, these
+                * conditions are not mutually exclusive and should be considered in
+                * this order.
+                */
+               if (IsA(target_query->utilityStmt, ExplainStmt))
                {
-                       ExplainStmt *stmt = (ExplainStmt *)(query->utilityStmt);
-
+                       ExplainStmt *stmt = (ExplainStmt *)target_query->utilityStmt;
+                       
                        Assert(IsA(stmt->query, Query));
                        target_query = (Query *)stmt->query;
 
@@ -1688,34 +1696,43 @@ get_query_string(ParseState *pstate, Query *query, Query **jumblequery)
                                target_query = (Query *)target_query->utilityStmt;
                }
 
-               if (IsA(target_query, CreateTableAsStmt))
+               /*
+                * JumbleQuery does  not accept  a Query that  has utilityStmt.  On the
+                * other  hand DeclareCursorStmt  is in  a  bit strange  shape that  is
+                * flipped upside down.
+                */
+               if (IsA(target_query, Query) &&
+                       target_query->utilityStmt &&
+                       IsA(target_query->utilityStmt, DeclareCursorStmt))
                {
                        /*
-                        * Use the the body query for CREATE AS. The Query for jumble also
-                        * replaced with the corresponding one.
+                        * The given Query cannot be modified so copy it and modify so that
+                        * JumbleQuery can accept it.
                         */
+                       Assert(IsA(target_query, Query) &&
+                                  target_query->commandType == CMD_SELECT);
+                       target_query = copyObject(target_query);
+                       target_query->utilityStmt = NULL;
+               }
+
+               if (IsA(target_query, CreateTableAsStmt))
+               {
                        CreateTableAsStmt  *stmt = (CreateTableAsStmt *) target_query;
-                       PreparedStatement  *entry;
-                       Query                      *tmp_query;
 
                        Assert(IsA(stmt->query, Query));
-                       tmp_query = (Query *) stmt->query;
+                       target_query = (Query *) stmt->query;
 
-                       if (tmp_query->commandType == CMD_UTILITY &&
-                               IsA(tmp_query->utilityStmt, ExecuteStmt))
-                       {
-                               ExecuteStmt *estmt = (ExecuteStmt *) tmp_query->utilityStmt;
-                               entry = FetchPreparedStatement(estmt->name, true);
-                               p = entry->plansource->query_string;
-                               target_query = (Query *) linitial (entry->plansource->query_list);
-                       }
+                       /* strip out the top-level query for further processing */
+                       if (target_query->commandType == CMD_UTILITY &&
+                               target_query->utilityStmt != NULL)
+                               target_query = (Query *)target_query->utilityStmt;
                }
-               else
+
                if (IsA(target_query, ExecuteStmt))
                {
                        /*
-                        * Use the prepared query for EXECUTE. The Query for jumble also
-                        * replaced with the corresponding one.
+                        * Use the prepared query for EXECUTE. The Query for jumble
+                        * also replaced with the corresponding one.
                         */
                        ExecuteStmt *stmt = (ExecuteStmt *)target_query;
                        PreparedStatement  *entry;
@@ -1724,15 +1741,16 @@ get_query_string(ParseState *pstate, Query *query, Query **jumblequery)
                        p = entry->plansource->query_string;
                        target_query = (Query *) linitial (entry->plansource->query_list);
                }
-
-               /* We don't accept other than a Query other than a CMD_UTILITY */
+                       
+               /* JumbleQuery accespts only a non-utility Query */
                if (!IsA(target_query, Query) ||
-                       target_query->commandType == CMD_UTILITY)
+                       target_query->utilityStmt != NULL)
                        target_query = NULL;
 
                if (jumblequery)
                        *jumblequery = target_query;
        }
+
        /* Return NULL if the pstate is not identical to the top-level query */
        else if (strcmp(pstate->p_sourcetext, p) != 0)
                p = NULL;
@@ -2538,7 +2556,7 @@ pg_hint_plan_post_parse_analyze(ParseState *pstate, Query *query)
                        }
                }
 
-               /* retrun if we have hint here*/
+               /* retrun if we have hint here */
                if (current_hint_str)
                        return;
        }