ORA-00911 invalid character - oracle

Anyone help me with this error
declare
cursor cur1 is
select owner,table_name from dba_tables;
c1 cur1%rowtype;
str varchar2(1000);
begin
for c1 in cur1 loop
str:='analyze table '||c1.owner||'.'||c1.table_name||' list chained rows';
execute immediate str;
end loop;
end;
/
declare
*
ERROR at line 1:
ORA-00911: invalid character
ORA-06512: at line 9

You appear to have a table (or user/schema) identifier which does not conform to the usual pattern and the database object naming rules, and which must therefore have been created as a quoted identifier.
For example, a table name starting with a number, or with a space in the name - you'd need to check your data dictionary to find out exactly what it's tripping over, or add a debug before the execute immediate to do dbms_output.put_line(str);.
Whatever it is though, you can just quote the identifier in the analyze command too:
str:='analyze table "'||c1.owner||'"."'||c1.table_name||'" list chained rows';
So if your current query generates a command like:
analyze table MYSCHEMA.42 list chained rows
... where the 42 is an invalid identifier, the modified version would do:
analyze table "MYSCHEMA"."42" list chained rows
This will also take care of any mixed-case names, which would also cause the analyze to fail unless quoted.
This is why quoted identifiers are not recommended by Oracle and are usually disliked by anyone who has been forced to deal with them. The identifier has to be quoted whenever it is referenced anywhere, and be used with exactly the same case as when it was created. If you have a choice, don't use them.
It may not be your fault though. On my 11gR2 instance there's an entry in dba_tables for "SYS"."_default_auditing_options_" which breaks the naming rules by starting with an underscore, and was created quoted in lowercase. (And that seems to have been there since at least 8.0). Not sure manually analyzing SYS tables is necessarily a good idea anyway, it might be better to restrict this to your own schema(s).

Related

I'm trying to create a procedure in Pl/Sql and I'm getting this error

https://imgur.com/a/ll59wjx - Picture
I'm trying to calculate the current product stock.
I have product_reception table in which I can calculate my stock.
And sales (vanzari) table.
Posting code as an image is usually a bad idea.
Anyway: quite a few objections:
don't enclose procedure (or table, column, ...) name into double quotes
name parameters so that their name is different from column names, for example: not cod_pds in number but par_cod_pds in number
declare variable in the declaration section, which is between is and begin. Don't use var (key)word. It is a good idea to name them so that the name reflects the fact that these are local variables, such as l_stoc_pds number
don't use exec within a PL/SQL procedure, especially not to run a select statement. exec is used in SQL*Plus to run a PL/SQL procedure, such as exec calculstoclazi
don't select into a variable preceded by a colon, but simply name the variable
those two select statements are exactly the same; I have no idea what you meant to do by doing that. Besides, you preceded cod_pds with stoc_pds which is a variable name (so that's totally wrong); if a column name is to be preceded by something, that's table name (or its alias)
Therefore, code that might look like something valid is this; obviously, the result will be 0 (zero). As I told you, those two selects are exactly the same.
create or replace procedure calculstoclazi
(par_cod_pds in number,
par_rezultat out number
)
is
l_stocs_pds number;
l_total_vanzare number;
begin
select sum(cantitate)
into l_stoc_pds
from receptie_marfa
where cod_pds = par_cod_pds;
select sum(cantitate)
into l_total_vanzare
from receptie_marfa
where cod_pds = par_cod_pds;
par_rezultat := l_stoc_pds - l_total_vanzare;
end;

Using regexp_replace to prevent SQL injection

We have thousands of oracle packages that contain a map_products procedure.
We have a table that stores the list of oracle packages a customer would like that map_products run for.
The process that runs them uses dynamic SQL like this:
select sanitize(package_name)
into v_package_name
from custom_plugins
where id = p_id;
execute immediate '
begin
'||v_package_name||'.map_products;
end;
';
The sanitize function above is meant to prevent SQL injection.
Here is the function definition:
function sanitize(p_string in varchar2) return varchar2
is
begin
return regexp_replace(upper(p_string),
'(ALTER|MERGE|CREATE|SELECT|INSERT|UPDATE|DELETE|MODIFY|DROP|ENABLE|DISABLE|;)');
end;
Now we realize this is a dangerous approach in the long run and are planning to redo the entire process. However, for the time being, is there any easy way that this regexp_replace can be circumvented allowing SQL injection?
More specifically, we want to make sure that a semicolon cannot be passed in. Does the above ensure that?
Use the string:
DRDROPOP your_package_name
The replace will only replace DROP once leaving you with:
DROP your_package_name
I suggest whitelisting instead of regular expressions.
Check the input against the system tables.
select object_name
from dba_objects
where owner = 'SYS'
and object_type = 'PACKAGE'
and object_name = :p_string;
If you can't find a match, then it isn't a known package, so don't use it.
I think removing the ; will be a first approach to avoid the sql injection. But please consider this possible strategy:
Extract with regexp a valid package name from the input(for example, checking that you have alphanumeric characters, or "_", or any other character allowed in a package name but nothing else).
With the output from previous step, check that the package is actually an object in the database (querying user_object).
At this point you will have a valid package name (if any) and you could use it in the dynamic statement.
You already said that your approach was dangerous. I just want to make sure that you're aware that it'd be problematic with a package with a name containing any of the words in your regexp (salaryUPDATEr, for example)
As the other posters above have commented blacklisting is going to be quite easy to bypass.
Using whitelist validation is always ideal. If that's not feasible, and since this is Oracle, the best option is to use the built in dbms_assert.enquote_name - this safely enquotes the value (and checks for embedded quotes).
For more info on DBMS_ASSERT see:
https://oracle-base.com/articles/10g/dbms_assert_10gR2#ENQUOTE_NAME
Or for much more in depth on preventing SQL injection see:
http://www.oracle.com/technetwork/database/features/plsql/overview/how-to-write-injection-proof-plsql-1-129572.pdf
You can use the DBMS_ASSERT package.
Since the 10g version, Oracle provides the DBMS_ASSERT package. It contains functions that can be used to validate user input.
Example (SQL Injection attempt)
SELECT description FROM products WHERE name=DBMS_ASSERT.ENQUOTE_LITERAL('abc'' OR 1=1--');
ERROR RETURNED.
ORA-06502: PL/SQL: numeric or value error
You can find more information at link.

how to insert in oracle 10g database and returns the ID generated using stored procedure

I am very new to oracle's sql developer (since we've studied mysql) as well as in programming. I've searched in this website the answer to my question but I really can't understand the solutions provided.
What I want is to return the ID generated after inserting an object from java into the database. I'm using mybatis and oracle 10g database. I've already created the table and its columns.
Here's my code for the mapper
<insert id="addUser" parameterType="User" statementType="CALLABLE">
{ CALL addUserSP(
#{user.surname, javaType=String, jdbcType=VARCHAR, mode=IN},
#{user.firstName, javaType=String, jdbcType=VARCHAR, mode=IN},
#{userId, javaType=Integer, jdbcType=NUMBER, mode=OUT}
)}
</insert>
Here's my stored procedure (and I've already create a package named 'CREATEUSER')
PROCEDURE ADDUSERSP
( surname IN VARCHAR2,
firstName IN VARCHAR2,
userId OUT NUMBER
) AS
BEGIN
INSERT INTO users("surname", "first_name")
VALUES (surname, firstName);
RETURNING user_id INTO userId;
END ADDUSERSP;
According to what I've found here, it seems that I need to create a trigger(?) and sequence(?) to make the user_id auto increment whenever I add new data into the table. However, I have no idea how to do it.
Here are my questions:
Is my stored procedure right? Are the codes incomplete? I mean, I have not declared the package in the mapper and I've seen that it is needed (?), something like this { CALL [CreateUser].[addUserSP]( blah blah.... Should I write a sequence and trigger or there is an easy way to make the primary key user_id to be auto incremented? Kindly also check the syntax. I have a lot of problems in syntax.
Thank you so much!
To emulate MySQL AUTO_INCREMENT in Oracle, that pattern (as you found) does use a SEQUENCE object and a BEFORE INSERT trigger.
As a demonstration, something like this for the sequence object:
CREATE SEQUENCE myseq START WITH 1 INCREMENT BY 1 ;
And something like this for the before insert trigger:
CREATE TRIGGER users_bi
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
IF :NEW.id IS NULL THEN
SELECT myseq.NEXTVAL INTO :NEW.id FROM DUAL;
END IF;
END
As far as the procedure, I'm not a big fan of extra PL/SQL blocks that wrap a SQL INSERT statement.
It looks like you have an extra semicolon, before RETURNING. That clause is part of the INSERT statement, not a separate statement.
One big gotcha to be aware of is that SQL statements within a PL/SQL block can reference both columns and PL/SQL variables. When variables have the same names as columns, you will likely encounter behavior you didn't expect.
Typically PL/SQL author use a naming convention for variables that reduces the likelihood of name collisions. We frequently see variables with names like v_surname. (Personally, I use a slightly different convention, but the variable names "look like" variable names, not column references. And I don't name columns following the pattern I use for variables.)
The double quotes around the identifiers are acceptable, but this does make the identifiers case sensitive. When identifiers aren't enclosed in double quotes, Oracle treats them as if they were UPPER CASE. Just make sure that your table was defined with lower case column names.

Double quotes inside single quotes in oracle statement

I'm having the following problem with an old database. We migrated from sql to oracle recently and I'm having trouble with an insert statement where the column name is "default". Any ideas (I'm not allowed to change the column name, that would be by far the best solution!)?
It looks somehow like this, only with a billion more columns and it's inside a large if-when-else construction for validating issues, so I can't drop the execute immediate.
EXECUTE IMMEDIATE 'INSERT INTO trytable (ID, "DEFAULT") VALUES (''monkey1'', 0)'
I don't think the problem comes from your column name, as shown in this working example:
SQL> CREATE TABLE trytable (ID VARCHAR2(10), "DEFAULT" NUMBER);
Table created
SQL> BEGIN
2 EXECUTE IMMEDIATE
3 'INSERT INTO trytable (ID, "DEFAULT") VALUES (''monkey1'', 0)';
4 END;
5 /
PL/SQL procedure successfully completed
Technically, you can have a table column name named DEFAULT, even if it's generally a bad idea that will lead to confusion. You will only be able to interact with it through the double-quote " syntax because DEFAULT is a reserved word.
If you specify double quotes around identifiers, Oracle will treat them as case-sensitive, so you have to make sure that they match the table specs.
In your case, it would help to have the specific error message.
The below will executes if your column name is "DEFAULT":
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO TRYTABLE(ID, "DEFAULT")VALUES(''monkey1'',0)';
END;
"DEFAULT" and "default" makes difference.

ORA-01747: invalid user.table.column, table.column, or column specification

Get the above error when the execute immediate is called in a loop
Update CustomersPriceGroups set 1AO00=:disc Where cuno=:cuno
Parameters: disc=66 cuno=000974
Update CustomersPriceGroups set 1AP00=:disc Where cuno=:cuno
Parameters: disc=70.5 cuno=000974
Update CustomersPriceGroups set 1AQ00=:disc Where cuno=:cuno
Parameters: disc=66 cuno=000974
Update CustomersPriceGroups set 1ZA00=:disc Where cuno=:cuno
Parameters: disc=60 cuno=000974
What does this mean ?
Here is the code fragment
c:=PriceWorx.frcPriceListCustomers('020','221');
LOOP
fetch c into comno,cuno,nama,cpls;
exit when c%notfound;
dbms_output.put_Line(cuno);
g:=priceWorx.frcPriceListItemGroups('020','221');
d:=priceworx.frcCustomerDiscounts('020','221',cuno);
loop
fetch g into comno,cpgs,n;
fetch d into comno,cpls,cuno,cpgs,stdt,tdat,qanp,disc,src;
--dbms_output.put(chr(9)||cpgs);
sQ:='Update saap.CustomersPriceGroups set "'|| trim(cpgs)||'"=:disc '
|| ' Where cuno=:cuno';
execute immediate sQ using disc,cuno;
commit;
dbms_output.put_line( sQ );
dbms_output.put_line( chr(9)||'Parameters: disc='|| disc||' cuno='||cuno);
exit when g%notfound;
end loop;
close g;
close d;
end loop;
check your query for double comma.
insert into TABLE_NAME (COLUMN1, COLUMN2,,COLUMN3) values(1,2,3);
(there is extra comma after COLUMN2).
Update: recently (some people have special talents) i succeed to get same exception with new approach:
update TABLE_NAME set COLUMN1=7, set COLUMN2=8
(second SET is redundant)
Unquoted identifiers must begin with an alphabetic character (see rule 6 here). You're trying to assign a value to a column with a name starting with a number 1AO00, 1AP00 etc.
Without seeing the table definition for CustomersPriceGroups we don't know if it has columns with those names. If it does then they must have been created as quoted identifiers. If so you'll have to refer to them (everywhere) with quotes, which is not ideal - makes the code a bit harder to read, makes it easy to make a mistake like this, and can be hard to spot what's wrong. Even Oracle say, on the same page:
Note: Oracle does not recommend using quoted identifiers for database
object names. These quoted identifiers are accepted by SQL*Plus, but
they may not be valid when using other tools that manage database
objects.
In you code you appear to be using quotes when you assign sQ, but the output you show doesn't; but it doesn't have the saap. schema identifier either. That may be because you're not running the version of the code you think, but might just have been
lost if you retyped the data instead of pasting it - you're not showing the earlier output of c.cuno either. But it's also possible you have, say, the case of the column name wrong.
If the execute is throwing the error, you won't see the command being executed that time around the loop because the debug comes after it - you're seeing the successful values, not the one that's breaking. You need to check all the values being returned by the functions; I suspect that g is returning a value for cpgs that actually isn't a valid column name.
As #ninesided says, showing more information, particularly the full exception message, will help identify what's wrong.
It means that the Oracle parser thinks that one of your columns is not valid. This might be because you've incorrectly referenced a column, the column name is reserved word, or because you have a syntax error in the UPDATE statement that makes Oracle think that something which is not a column, is a column. It would really help to see the full statement that is being executed, the definition of the CustomersPriceGroups table and the full text of the exception being raised, as it will often tell which column is at fault.
if you add a extra "," at the end of the set statement instead of a syntax error, you will get ORA-01747, which is very very odd from Oracle
e.g
update table1
set col1 = 'Y', --this odd 1
where col2 = 123
and col3 = 456
In addition to reasons cited in other answers here, you may also need to check that none of your table column names have a name which is considered a special/reserved word in oracle database.
In my case I had a table column name uid. uid is a reserved word in oracle and therefore I was getting this error.
Luckly, my table was a new table and I had no data in it. I was a able to use oracle DROP table command to delete the table and create a new one with a modified name for the problem column.
I also had trouble with renaming the problem column as oracle wouldn't let me and kept throwing errors.
You used oracle keyword in your SQL statement
And I was writing query like. I had to remove [ and ]
UPDATE SN.TableName
SET [EXPIRY_DATE] = systimestamp + INTERVAL '12' HOUR,
WHERE [USER_ID] ='12345'
We recently moved from SQL Server to Oracle.
The cause may also be when you group by a different set of columns than in select for example:
select tab.a, tab.b, count(*)
from ...
where...
group by tab.a, tab.c;
ORA-01747: invalid user.table.column, table.column, or column
specification
You will get when you miss the column relation when you compare both column id your is will not be the same check both id in your database
Here is the sample Example which I was facing:
UPDATE TABLE_NAME SET APPROVED_BY='1000',CHECK_CONDITION=ID, WHERE CONSUMER_ID='200'
here Issue you will get when 'CHECK_CONDITION' and 'ID' both column id will no same
If both id will same this time your query will execute fine, Check id Id both Column you compare in your code.
For me, the issue was due to use to column name "CLUSTER" which is a reserved word in Oracle. I was trying to insert into the column. Renaming the column fixed my issue.
insert into table (JOB_NAME, VERSION, CLUSTER, REPO, CREATE_TS) VALUES ('abc', 169, 'abc.war', '1.3', 'test.com', 'test', '26-Aug-19 04.27.09.000000949 PM')
Error at Command Line : 1 Column : 83
Error report -
SQL Error: ORA-01747: invalid user.table.column, table.column, or column specification
In my case, I had some.* in count. like count(dr.*)

Resources