The reason the first one simply prints out is that you are printing a string. So in you example 1, :REPORTNAME is just a string, and does not represent a variable. However, when you go to run it through execute immediate, it tries to treat it as a variable, to which it cannot find a match.
Take out the colon part, and just put reportname as it appears in your parameter declaration list. If you are trying to run this outside of Forms or Reports, you are going to get that error, b/c you need to "define" the bind variable :REPORTNAME. In SQL*PLUS i think you use the variable command or var for short.
But to summarize, take out the colon and it should work fine.
So, I noticed that I had 'REPORTNAME' twice in the code, and I wasn't sure what would happen once I removed the colon, since both strings looked identical at that point, so I exchanged the parameter for RPTNAME, and I still get an error of one type
SQL> CREATE OR REPLACE PROCEDURE forbesc.writerptline (
2 tablename IN VARCHAR2,
3 rptname IN VARCHAR2
7 EXECUTE IMMEDIATE 'INSERT INTO '
8 || tablename
9 || ' (REPORTNAME) '
10 || 'VALUES (rptname)';
2 forbesc.writerptline('forbesc.rpt','my report');
ERROR at line 1:
ORA-00984: column not allowed here
ORA-06512: at "FORBESC.WRITERPTLINE", line 7
ORA-06512: at line 2
EXECUTE IMMEDIATE 'INSERT INTO ' || tablename || ' (REPORTNAME) VALUES (:b1)'
Obviously this particular example is just a test case. Passing object names around would normally indicate a design weakness. It is not generally the calling procedure's business which database objects are used.