2) the hash is used to find the statement faster. the hash value is just a surrogate key used to identify the sql statement.
3)
a) no, plsql just caches cursors - when you say "close cursor C", plsql says "No, I won't, I'll pretend I did to make you happy, but I'm keeping this open in case you execute it again - it is more efficient that way"
session cached cursors is used by plsql to limit the number of cursors it keeps physically open, but - it keeps them open.
b) I don't know how else to say it. In plsql, if you use static sql (EG: NOT DYNAMIC) it is impossible to not use bind variables correctly. Therefore, you get the best possible chances for reuse of SQL - shared SQL.
4) in plsql, in order to execute
where x = 5
where x = 6
where x = 7
...
where x = 500000000
you would either
a) have to type in 500000000 sql statements and compile it. You won't do that.
b) use dynamic sql and build the SQL on the fly.
If you use dynamic sql, you can bind incorrectly (by not binding). If you use STATIC SQL (sql known at compile time), you have to bind (you will reference a plsql variable.
eg:
for i in 1 .. 5000000
loop
execute immediate 'select count(*) from t where x='||i into N;
select count(*) into N from t where x=i;
end loop;
the first select is dynamic sql, it will generate 5,000,000 UNIQUE sql statements, flood the shared pool and kill the system.
the second is "static sql" in plqsl, it will generate ONE statement and just use it over and over and over....
the second approach is correct, the first is very very very bad.