OSDN Git Service

Added EXECUTE command to PL/pgSQL for execution of
authorJan Wieck <JanWieck@Yahoo.com>
Thu, 31 Aug 2000 13:26:16 +0000 (13:26 +0000)
committerJan Wieck <JanWieck@Yahoo.com>
Thu, 31 Aug 2000 13:26:16 +0000 (13:26 +0000)
dynamic SQL and utility statements.

Jan

src/pl/plpgsql/src/gram.y
src/pl/plpgsql/src/pl_comp.c
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/pl_funcs.c
src/pl/plpgsql/src/plpgsql.h
src/pl/plpgsql/src/scan.l

index e76ddec..99f7a1b 100644 (file)
@@ -4,7 +4,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.10 2000/06/05 07:29:14 tgl Exp $
+ *    $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.11 2000/08/31 13:26:15 wieck Exp $
  *
  *    This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -113,6 +113,7 @@ static      PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 %type <stmt>   stmt_assign, stmt_if, stmt_loop, stmt_while, stmt_exit
 %type <stmt>   stmt_return, stmt_raise, stmt_execsql, stmt_fori
 %type <stmt>   stmt_fors, stmt_select, stmt_perform
+%type <stmt>   stmt_dynexecute, stmt_dynfors
 
 %type <dtlist> raise_params
 %type <ival>   raise_level, raise_param
@@ -134,6 +135,7 @@ static      PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 %token K_ELSE
 %token K_END
 %token K_EXCEPTION
+%token K_EXECUTE
 %token K_EXIT
 %token K_FOR
 %token K_FROM
@@ -568,6 +570,10 @@ proc_stmt  : pl_block
                        { $$ = $1; }
                | stmt_execsql
                        { $$ = $1; }
+               | stmt_dynexecute
+                       { $$ = $1; }
+               | stmt_dynfors
+                       { $$ = $1; }
                | stmt_perform
                        { $$ = $1; }
                ;
@@ -844,6 +850,35 @@ stmt_fors  : opt_label K_FOR lno fors_target K_IN K_SELECT expr_until_loop loop_b
                        $$ = (PLpgSQL_stmt *)new;
                    }
 
+stmt_dynfors : opt_label K_FOR lno fors_target K_IN K_EXECUTE expr_until_loop loop_body
+                   {
+                       PLpgSQL_stmt_dynfors    *new;
+
+                       new = malloc(sizeof(PLpgSQL_stmt_dynfors));
+                       memset(new, 0, sizeof(PLpgSQL_stmt_dynfors));
+
+                       new->cmd_type = PLPGSQL_STMT_DYNFORS;
+                       new->lineno   = $3;
+                       new->label    = $1;
+                       switch ($4->dtype) {
+                           case PLPGSQL_DTYPE_REC:
+                               new->rec = $4;
+                               break;
+                           case PLPGSQL_DTYPE_ROW:
+                               new->row = (PLpgSQL_row *)$4;
+                               break;
+                           default:
+                               plpgsql_comperrinfo();
+                               elog(ERROR, "unknown dtype %d in stmt_dynfors", $4->dtype);
+                       }
+                       new->query = $7;
+                       new->body  = $8;
+
+                       plpgsql_ns_pop();
+
+                       $$ = (PLpgSQL_stmt *)new;
+                   }
+
 fors_target    : T_RECORD
                    {
                        $$ = yylval.rec;
@@ -1028,6 +1063,19 @@ stmt_execsql     : execsql_start lno
                    }
                ;
 
+stmt_dynexecute        : K_EXECUTE lno expr_until_semi
+                       {
+                               PLpgSQL_stmt_dynexecute *new;
+
+                       new = malloc(sizeof(PLpgSQL_stmt_dynexecute));
+                       new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
+                       new->lineno   = $2;
+                       new->query    = $3;
+
+                       $$ = (PLpgSQL_stmt *)new;
+                       }
+               ;
+
 execsql_start  : T_WORD
                    { $$ = strdup(yytext); }
                | T_ERROR
index cc4196f..bed9589 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.22 2000/08/03 16:34:57 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.23 2000/08/31 13:26:16 wieck Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -159,8 +159,8 @@ plpgsql_compile(Oid fn_oid, int functype)
 
        function->fn_functype = functype;
        function->fn_oid = fn_oid;
-       function->fn_name = DatumGetCString(DirectFunctionCall1(nameout,
-                                               NameGetDatum(&(procStruct->proname))));
+       function->fn_name = strdup(DatumGetCString(DirectFunctionCall1(nameout,
+                                               NameGetDatum(&(procStruct->proname)))));
 
        switch (functype)
        {
index 6c761c5..7740c27 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.28 2000/08/24 03:29:15 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.29 2000/08/31 13:26:16 wieck Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -100,6 +100,10 @@ static int exec_stmt_raise(PLpgSQL_execstate * estate,
                                PLpgSQL_stmt_raise * stmt);
 static int exec_stmt_execsql(PLpgSQL_execstate * estate,
                                  PLpgSQL_stmt_execsql * stmt);
+static int exec_stmt_dynexecute(PLpgSQL_execstate * estate,
+                                 PLpgSQL_stmt_dynexecute * stmt);
+static int exec_stmt_dynfors(PLpgSQL_execstate * estate,
+                          PLpgSQL_stmt_dynfors * stmt);
 
 static void exec_prepare_plan(PLpgSQL_execstate * estate,
                                  PLpgSQL_expr * expr);
@@ -219,6 +223,12 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
                                        case PLPGSQL_STMT_EXECSQL:
                                                stmttype = "SQL statement";
                                                break;
+                                       case PLPGSQL_STMT_DYNEXECUTE:
+                                               stmttype = "execute statement";
+                                               break;
+                                       case PLPGSQL_STMT_DYNFORS:
+                                               stmttype = "for over execute statement";
+                                               break;
                                        default:
                                                stmttype = "unknown";
                                                break;
@@ -522,6 +532,12 @@ plpgsql_exec_trigger(PLpgSQL_function * func,
                                        case PLPGSQL_STMT_EXECSQL:
                                                stmttype = "SQL statement";
                                                break;
+                                       case PLPGSQL_STMT_DYNEXECUTE:
+                                               stmttype = "execute statement";
+                                               break;
+                                       case PLPGSQL_STMT_DYNFORS:
+                                               stmttype = "for over execute statement";
+                                               break;
                                        default:
                                                stmttype = "unknown";
                                                break;
@@ -995,6 +1011,14 @@ exec_stmt(PLpgSQL_execstate * estate, PLpgSQL_stmt * stmt)
                        rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
                        break;
 
+               case PLPGSQL_STMT_DYNEXECUTE:
+                       rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);
+                       break;
+
+               case PLPGSQL_STMT_DYNFORS:
+                       rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
+                       break;
+
                default:
                        error_info_stmt = save_estmt;
                        elog(ERROR, "unknown cmdtype %d in exec_stmt",
@@ -1853,6 +1877,234 @@ exec_stmt_execsql(PLpgSQL_execstate * estate,
 
 
 /* ----------
+ * exec_stmt_dynexecute                        Execute a dynamic SQL query not
+ *                                     returning any data.
+ * ----------
+ */
+static int
+exec_stmt_dynexecute(PLpgSQL_execstate * estate,
+                                 PLpgSQL_stmt_dynexecute * stmt)
+{
+       Datum           query;
+       bool            isnull = false;
+       Oid                     restype;
+       char       *querystr;
+       HeapTuple       typetup;
+       Form_pg_type typeStruct;
+       FmgrInfo        finfo_output;
+
+       /* ----------
+        * First we evaluate the string expression after the
+        * EXECUTE keyword. It's result is the querystring we have
+        * to execute.
+        * ----------
+        */
+       query = exec_eval_expr(estate, stmt->query, &isnull, &restype);
+       if (isnull)
+               elog(ERROR, "cannot EXECUTE NULL-query");
+
+       /* ----------
+        * Get the C-String representation.
+        * ----------
+        */
+       typetup = SearchSysCacheTuple(TYPEOID,
+               ObjectIdGetDatum(restype), 0, 0, 0);
+       if (!HeapTupleIsValid(typetup))
+               elog(ERROR, "cache lookup for type %u failed (1)", restype);
+       typeStruct = (Form_pg_type) GETSTRUCT(typetup);
+
+       fmgr_info(typeStruct->typoutput, &finfo_output);
+       querystr = DatumGetCString(FunctionCall3(&finfo_output,
+                               query,
+                               ObjectIdGetDatum(typeStruct->typelem),
+                               Int32GetDatum(-1)));
+
+       if(!typeStruct->typbyval)
+               pfree((void *)query);
+
+       /* ----------
+        * Call SPI_exec() without preparing a saved plan. 
+        * The returncode can be any OK except for OK_SELECT.
+        * ----------
+        */
+       switch(SPI_exec(querystr, 0))
+       {
+               case SPI_OK_UTILITY:
+               case SPI_OK_SELINTO:
+               case SPI_OK_INSERT:
+               case SPI_OK_UPDATE:
+               case SPI_OK_DELETE:
+                       break;
+
+               case SPI_OK_SELECT:
+                       elog(ERROR, "unexpected SELECT operation in EXECUTE of query '%s'",
+                                               querystr);
+                       break;
+
+               default:
+                       elog(ERROR, "unexpected error in EXECUTE for query '%s'",
+                                               querystr);
+                       break;
+       }
+
+       pfree(querystr);
+       return PLPGSQL_RC_OK;
+}
+
+
+/* ----------
+ * exec_stmt_dynfors                   Execute a dynamic query, assign each
+ *                                     tuple to a record or row and
+ *                                     execute a group of statements
+ *                                     for it.
+ * ----------
+ */
+static int
+exec_stmt_dynfors(PLpgSQL_execstate * estate, PLpgSQL_stmt_dynfors * stmt)
+{
+       Datum           query;
+       bool            isnull = false;
+       Oid                     restype;
+       char       *querystr;
+       PLpgSQL_rec *rec = NULL;
+       PLpgSQL_row *row = NULL;
+       SPITupleTable *tuptab;
+       int                     rc;
+       int                     i;
+       int                     n;
+       HeapTuple       typetup;
+       Form_pg_type typeStruct;
+       FmgrInfo        finfo_output;
+
+       /* ----------
+        * Initialize the global found variable to false
+        * ----------
+        */
+       exec_set_found(estate, false);
+
+       /* ----------
+        * Determine if we assign to a record or a row
+        * ----------
+        */
+       if (stmt->rec != NULL)
+               rec = (PLpgSQL_rec *) (estate->datums[stmt->rec->recno]);
+       else
+       {
+               if (stmt->row != NULL)
+                       row = (PLpgSQL_row *) (estate->datums[stmt->row->rowno]);
+               else
+                       elog(ERROR, "unsupported target in exec_stmt_fors()");
+       }
+
+       /* ----------
+        * Evaluate the string expression after the
+        * EXECUTE keyword. It's result is the querystring we have
+        * to execute.
+        * ----------
+        */
+       query = exec_eval_expr(estate, stmt->query, &isnull, &restype);
+       if (isnull)
+               elog(ERROR, "cannot EXECUTE NULL-query");
+
+       /* ----------
+        * Get the C-String representation.
+        * ----------
+        */
+       typetup = SearchSysCacheTuple(TYPEOID,
+               ObjectIdGetDatum(restype), 0, 0, 0);
+       if (!HeapTupleIsValid(typetup))
+               elog(ERROR, "cache lookup for type %u failed (1)", restype);
+       typeStruct = (Form_pg_type) GETSTRUCT(typetup);
+
+       fmgr_info(typeStruct->typoutput, &finfo_output);
+       querystr = DatumGetCString(FunctionCall3(&finfo_output,
+                               query,
+                               ObjectIdGetDatum(typeStruct->typelem),
+                               Int32GetDatum(-1)));
+
+       if(!typeStruct->typbyval)
+               pfree((void *)query);
+
+       /* ----------
+        * Run the query
+        * ----------
+        */
+       if (SPI_exec(querystr, 0) != SPI_OK_SELECT)
+               elog(ERROR, "FOR ... EXECUTE query '%s' was no SELECT", querystr);
+       pfree(querystr);
+
+       n = SPI_processed;
+
+       /* ----------
+        * If the query didn't return any row, set the target
+        * to NULL and return.
+        * ----------
+        */
+       if (n == 0)
+       {
+               exec_move_row(estate, rec, row, NULL, NULL);
+               return PLPGSQL_RC_OK;
+       }
+
+       /* ----------
+        * There are tuples, so set found to true
+        * ----------
+        */
+       exec_set_found(estate, true);
+
+       /* ----------
+        * Now do the loop
+        * ----------
+        */
+       tuptab = SPI_tuptable;
+       SPI_tuptable = NULL;
+
+       for (i = 0; i < n; i++)
+       {
+               /* ----------
+                * Assign the tuple to the target
+                * ----------
+                */
+               exec_move_row(estate, rec, row, tuptab->vals[i], tuptab->tupdesc);
+
+               /* ----------
+                * Execute the statements
+                * ----------
+                */
+               rc = exec_stmts(estate, stmt->body);
+
+               /* ----------
+                * Check returncode
+                * ----------
+                */
+               switch (rc)
+               {
+                       case PLPGSQL_RC_OK:
+                               break;
+
+                       case PLPGSQL_RC_EXIT:
+                               if (estate->exitlabel == NULL)
+                                       return PLPGSQL_RC_OK;
+                               if (stmt->label == NULL)
+                                       return PLPGSQL_RC_EXIT;
+                               if (strcmp(stmt->label, estate->exitlabel))
+                                       return PLPGSQL_RC_EXIT;
+                               estate->exitlabel = NULL;
+                               return PLPGSQL_RC_OK;
+
+                       case PLPGSQL_RC_RETURN:
+                               return PLPGSQL_RC_RETURN;
+
+                       default:
+                               elog(ERROR, "unknown rc %d from exec_stmts()", rc);
+               }
+       }
+
+       return PLPGSQL_RC_OK;
+}
+
+
+/* ----------
  * exec_assign_expr                    Put an expressions result into
  *                                     a variable.
  * ----------
index 0b191ff..dc1a2f4 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.6 2000/06/14 18:18:00 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.7 2000/08/31 13:26:16 wieck Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -388,6 +388,8 @@ static void dump_exit(PLpgSQL_stmt_exit * stmt);
 static void dump_return(PLpgSQL_stmt_return * stmt);
 static void dump_raise(PLpgSQL_stmt_raise * stmt);
 static void dump_execsql(PLpgSQL_stmt_execsql * stmt);
+static void dump_dynexecute(PLpgSQL_stmt_dynexecute * stmt);
+static void dump_dynfors(PLpgSQL_stmt_dynfors * stmt);
 static void dump_expr(PLpgSQL_expr * expr);
 
 
@@ -442,6 +444,12 @@ dump_stmt(PLpgSQL_stmt * stmt)
                case PLPGSQL_STMT_EXECSQL:
                        dump_execsql((PLpgSQL_stmt_execsql *) stmt);
                        break;
+               case PLPGSQL_STMT_DYNEXECUTE:
+                       dump_dynexecute((PLpgSQL_stmt_dynexecute *) stmt);
+                       break;
+               case PLPGSQL_STMT_DYNFORS:
+                       dump_dynfors((PLpgSQL_stmt_dynfors *) stmt);
+                       break;
                default:
                        elog(ERROR, "plpgsql_dump: unknown cmd_type %d\n", stmt->cmd_type);
                        break;
@@ -663,6 +671,34 @@ dump_execsql(PLpgSQL_stmt_execsql * stmt)
 }
 
 static void
+dump_dynexecute(PLpgSQL_stmt_dynexecute * stmt)
+{
+       dump_ind();
+       printf("EXECUTE ");
+       dump_expr(stmt->query);
+       printf("\n");
+}
+
+static void
+dump_dynfors(PLpgSQL_stmt_dynfors * stmt)
+{
+       int                     i;
+
+       dump_ind();
+       printf("FORS %s EXECUTE ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
+       dump_expr(stmt->query);
+       printf("\n");
+
+       dump_indent += 2;
+       for (i = 0; i < stmt->body->stmts_used; i++)
+               dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
+       dump_indent -= 2;
+
+       dump_ind();
+       printf("    ENDFORS\n");
+}
+
+static void
 dump_expr(PLpgSQL_expr * expr)
 {
        int                     i;
index f424698..e48a56c 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.9 2000/05/28 17:56:28 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.10 2000/08/31 13:26:16 wieck Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -91,7 +91,9 @@ enum
        PLPGSQL_STMT_EXIT,
        PLPGSQL_STMT_RETURN,
        PLPGSQL_STMT_RAISE,
-       PLPGSQL_STMT_EXECSQL
+       PLPGSQL_STMT_EXECSQL,
+       PLPGSQL_STMT_DYNEXECUTE,
+       PLPGSQL_STMT_DYNFORS
 };
 
 
@@ -319,6 +321,18 @@ typedef struct
 
 
 typedef struct
+{                                                              /* FOR statement running over EXECUTE   */
+       int                     cmd_type;
+       int                     lineno;
+       char       *label;
+       PLpgSQL_rec *rec;
+       PLpgSQL_row *row;
+       PLpgSQL_expr *query;
+       PLpgSQL_stmts *body;
+}                      PLpgSQL_stmt_dynfors;
+
+
+typedef struct
 {                                                              /* SELECT ... INTO statement            */
        int                     cmd_type;
        int                     lineno;
@@ -366,6 +380,14 @@ typedef struct
 }                      PLpgSQL_stmt_execsql;
 
 
+typedef struct
+{                                                              /* Dynamic SQL string to execute */
+       int                     cmd_type;
+       int                     lineno;
+       PLpgSQL_expr *query;
+}                      PLpgSQL_stmt_dynexecute;
+
+
 typedef struct PLpgSQL_function
 {                                                              /* Complete compiled function     */
        Oid                     fn_oid;
index a3eae57..73b6050 100644 (file)
@@ -4,7 +4,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.5 2000/08/22 14:59:28 tgl Exp $
+ *    $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.6 2000/08/31 13:26:16 wieck Exp $
  *
  *    This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -100,6 +100,7 @@ default                     { return K_DEFAULT;                     }
 else                   { return K_ELSE;                        }
 end                            { return K_END;                         }
 exception              { return K_EXCEPTION;           }
+execute                        { return K_EXECUTE;                     }
 exit                   { return K_EXIT;                        }
 for                            { return K_FOR;                         }
 from                   { return K_FROM;                        }