El problema es el ;
carácter en 'SELECT * FROM DUAL;'
.
De documentación :
execute_immediate_statement ::=
EXECUTE_IMMEDIATE dynamic_string
{
INTO { define_variable [, define_variable ...] | record_name }
| BULK COLLECT INTO { collection_name [, collection_name ...] | :host_array_name }
}
[ USING [ IN | OUT | IN OUT ] bind_argument
[, [ IN | OUT | IN OUT ] bind_argument] ... ] [ returning_clause ] ;
... donde dynamic_string
es (énfasis mío):
Dado que no aceptará varias declaraciones a menos que las incluya en un solo bloque PL/SQL, el ;
no se espera un separador.
Hay una mejor explicación en Uso de la instrucción EXECUTE IMMEDIATE en PL/SQL :