I have an anonymous pl/sql block in an sql file and I want to execute and assign values to it in Java. My sql block looks like this
DECLARE
someInput1 NUMBER(1);
someInput2 NUMBER(2);
someString1 VARCHAR(100);
BEGIN
someInput1 := ‘&1’;
someInput2 := ‘&2’;
--get name in table A
BEGIN
SELECT a.value INTO someString1
FROM TABLE_A a
WHERE a.id = someInput1;
END;
UPDATE TABLE_B b
SET b.someStringRow = someString1
WHERE b.someIntRow = someInput2;
COMMIT;
END;
/
exit;
What I am planning to do is load the sql file in a Java String, change ‘&1’ to ?1 and execute it as a CallableStatement. However, I am getting
PLS-00103: Encountered the symbol “” when expecting one of the following
begin function package pragma procedure subtype us <an identifier> <a double quoted delimited identifier> form current cursor
Error occured at lines in DECLARE section
Is my approach an acceptable solution, if yes, what may be wrong in my approach?
Are there other better solution for my problem? Thanks
you have to remove quote marks, and replace &1 with :1, and you should be fine, also, you will need remove '/' and exit; and they relate to sqlplus and not to pl/sql directly
Related
I'm using iBatis' ScriptRunner to execute scripts on an Oracle database. The first script is executed fine, but the second one which has triggers in it returns:
Cause: java.sql.SQLSyntaxErrorException: ORA-00900: invalid SQL statement
The part of the script which returns this error is executed without any errors on SQL Developer:
.
.
.
create table MG_MSGALR
(
ID VARCHAR2(30) not null,
V_GRAV VARCHAR2(3),
constraint PK_MG_MSGALR primary key (ID) using index tablespace B_INDEX
);
CREATE OR REPLACE TRIGGER UC_JAR_LST_TRIGGER
BEFORE INSERT
ON UC_JAR_LST
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT UC_JAR_LST_SEQ.nextval INTO :NEW.ID FROM dual;
END;
/
CREATE OR REPLACE TRIGGER UC_UPD_LST_TRIGGER
BEFORE INSERT
ON UC_UPD_LST
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT UC_UPD_LST_SEQ.nextval INTO :NEW.ID FROM dual;
END;
/
Here's how I execute the script from my side:
Boolean procedure = StringUtils.endsWith(FilenameUtils.getBaseName(file.getName()), "procedure") || StringUtils.endsWith(FilenameUtils.getBaseName(file.getName()), "trigger");
runner.setSendFullScript(procedure);
runner.runScript(new FileReader(file));
I noticed that the Boolean procedure's value is always false even when the script has triggers in it, and so I tried to force ScriptRunner to send it as a full script just to see if it goes through or not and i got the following error instead:
CREATE OR REPLACE TRIGGER UC_UPD_LST_TRIGGER
BEFORE INSERT
ON UC_UPD_LST
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT UC_UPD_LST_SEQ.nextval INTO :NEW.ID FROM dual;
END;
/
. Cause: java.sql.SQLSyntaxErrorException: ORA-00933: SQL command not properly ended
Could somebody please tell me what am I doing wrong here? Should add some sort of delimiter in the file right before when the trigger creation is supposed to start (which is now at the very end of the file).
In case someone else runs into the same problem. When you have a hybrid script (which means it has both normal queries and procedures or triggers), and if you're trying to execute it using myBatis from Java, all you need to do is leave all of your procedures at the end of your script and put delimiters before and after them to let SQL know it should be executed as a block and not line by line. So here's how I added my delimiters:
-- Change the delimiter to '$'
-- #DELIMITER $
CREATE OR REPLACE TRIGGER UC_JAR_LST_TRIGGER
BEFORE INSERT
ON UC_JAR_LST
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT UC_JAR_LST_SEQ.nextval INTO :NEW.ID FROM dual;
-- Change the delimiter back to ';'
-- #DELIMITER ;
END;
-- Change the delimiter to '$'
-- #DELIMITER $
CREATE OR REPLACE TRIGGER UC_UPD_LST_TRIGGER
BEFORE INSERT
ON UC_UPD_LST
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT UC_UPD_LST_SEQ.nextval INTO :NEW.ID FROM dual;
-- Change the delimiter back to ';'
-- #DELIMITER ;
END;
And the execution ended without errors.
I have a special case, in which the following PostgreSQL script is required to be called from java:
do
$$
DECLARE
xx VARCHAR(200);
xy VARCHAR(200);
xz VARCHAR(200);
yy VARCHAR(200);
BEGIN
xx := ?;
xy := ?;
call database_procedure(yy, yz, xx, xy);
? := yy;
? := yz;
END;
$$
This script is passed to CallableStatement in the following way, and the Input/Output parameters are binded with the callable statement.
CallableStatement cs = pgConn.prepareCall(sqlScript);
cs.setString(1,"param1");
cs.setString(2,"value2");
cs.registerOutParameter(3, Types.VARCHAR);
cs.registerOutParameter(4, Types.VARCHAR);
I get the issue on the line
cs.setString(1,"param1");
Issue: org.postgresql.util.PSQLException: The column index is out of range: 1, number of columns: 0.
Upon research i have found that, this issue is because the cs.setString is unable to find question mark(or parameter place holder).
Also, When i try simple query as following, it works.
CallableStatement cs = pgConn.prepareCall("call database_procedure(?,?,?,?)");
But according to my current scenario, I need a solution to executing the whole script as i mentioned, instead of only one call, because in different scenarios we are assigning values to out parameters based on the data returned by the procedure and so on.
Kindly help, so that, somehow the IN/INOUT parameters are passed to the sql script mentioned above.
I am working with TSP(Traveling salesmen problem) Solution in mysql.
for that we are going to develop procedure where i want to execute following query
-- variable coming from java
CREATE PROCEDURE solve_tsp(
inout ids varchar(21845);
)
begin
declare ret_ids varchar(21845);
-- some code
while length(ids) > 0 do
-- some assignment
SELECT to_id,distance into #l_tmp_id,#l_distance FROM mst_distance_matrix WHERE from_id =',#l_tmp_id,' AND
to_id IN (ids) -- ids is variable contains comma delimited string.
order by distance desc limit 1
-- concat value of to_id in ret_ids variable and then remove from ids variable
end while;
select ret_ids;
end;
You should look here.
http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-prepared-statements.html
Example:
PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
SET #a = 3;
SET #b = 4;
EXECUTE stmt1 USING #a, #b;
DEALLOCATE PREPARE stmt1;
See also:
Dynamic Query in MySQL
I am using Oracle 11g, I am executing Oracle sql script through java code. My SQL script may contain SQL statements(DDL or DML) or PL/SQL blocks, so I don't want to parse the script in my java code but used This solution to execute complete script at once. Following is the sample code, where SQLExec class is in ant jar.
This solution worked for most cases except that if sql script contains create or replace trigger it fails with java.sql.SQLSyntaxErrorException: ORA-00900: invalid SQL statement. I have also specified snippet of sql script which fails.
Please note that if I run same script through SQL Developer, it runs fine.
Following is the Java code:
private void executeSql(String sqlFilePath) {
final class SqlExecuter extends SQLExec {
public SqlExecuter() {
Project project = new Project();
project.init();
setProject(project);
setTaskType("sql");
setTaskName("sql");
}
}
SqlExecuter executer = new SqlExecuter();
executer.setSrc(new File(sqlFilePath));
executer.setDriver(args.getDriver());
executer.setPassword(args.getPwd());
executer.setUserid(args.getUser());
executer.setUrl(args.getUrl());
executer.execute();
}
SQL Script snippet:
......
......
CREATE OR REPLACE TRIGGER MY_TRG
BEFORE INSERT ON MY_TABLE
FOR EACH ROW
BEGIN
:NEW.MYNUMBER := MY_SEQUENCENUM.NEXTVAL;
END;
Following is the Exception trace:
Exception in thread "main" java.sql.SQLSyntaxErrorException: ORA-00900: invalid SQL statement
at org.apache.tools.ant.taskdefs.SQLExec.execute(SQLExec.java:398)
at com.kuldeep.OracleConnectionTest.executeSql(OracleConnectionTest.java:160)
at com.kuldeep.OracleConnectionTest.main(OracleConnectionTest.java:25)
Caused by: java.sql.SQLSyntaxErrorException: ORA-00900: invalid SQL statement
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:439)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:395)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:802)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:436)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:186)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:521)
at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:194)
at oracle.jdbc.driver.T4CStatement.executeForRows(T4CStatement.java:1000)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1307)
at oracle.jdbc.driver.OracleStatement.executeInternal(OracleStatement.java:1882)
at oracle.jdbc.driver.OracleStatement.execute(OracleStatement.java:1847)
at oracle.jdbc.driver.OracleStatementWrapper.execute(OracleStatementWrapper.java:301)
at org.apache.tools.ant.taskdefs.SQLExec.execSQL(SQLExec.java:499)
at org.apache.tools.ant.taskdefs.SQLExec.runStatements(SQLExec.java:470)
at org.apache.tools.ant.taskdefs.SQLExec$Transaction.runTransaction(SQLExec.java:664)
at org.apache.tools.ant.taskdefs.SQLExec$Transaction.access$000(SQLExec.java:627)
at org.apache.tools.ant.taskdefs.SQLExec.execute(SQLExec.java:370)
In the documentation it says:
Multiple statements can be provided, separated by semicolons (or the defined delimiter).
Therefore, using the semicolon character (;) as the default delimiter, SQLEXEC interprets the CREATE TRIGGER statement of your script as two statements, giving this error message as the result.
As #Reza Goodarzi mentioned the cause of invalid SQL statement is semicolon being used as the statement separator. So to solve my issue I am separating each statement with slash(/) as delimiter and followed these rules which I created myself:
Each SQL statement (not part of PL/SQL block) and PL/SQL block must end with a forwarded slash (/) in a new line.
SQL statement (not part of PL/SQL blocks) should not end with semicolon (;). I just removed semicolon from the end of statements.
For PL/SQL block do not remove the semicolon(;) from end of the block as well as from any statement contained within the block.
And by making these changes in my SQL Scripts I executed (using jdbc) each PL/SQL block and each SQL statement (not part of PL/SQL block) at a time by parsing the file myself instead of using SQLExec or any other external api/library.
I think you need to change your trigger to set your new ID
create or replace trigger MY_TRG
BEFORE insert MY_TABLE
for each row
begin
if (:new.MYNUMBER is null) then
select MY_SEQUENCENUM.nextval
into :new.MYNUMBER
from DUAL;
end if;
end;
/
or this:
create or replace trigger TG_BIU_TABLE1
before insert or update on TABLE1
for each row
begin
if (:new.ID1 is null) then
select SQ_TABLE1.nextval
into :new.ID1
from DUAL
end if
end
/
You can also add a delimiter in the execute statement, as so:
......
......
DELIMITER $$
CREATE OR REPLACE TRIGGER MY_TRG
BEFORE INSERT ON MY_TABLE
FOR EACH ROW
BEGIN
:NEW.MYNUMBER := MY_SEQUENCENUM.NEXTVAL;
END; $$
......
I also left the final part of the script just for the triggers and procedures, as the delimiter is used onward.
That did the trick for me. Courtesy of SQL Developer´s Migration tool.
When executing pl/sql im obtaining an error :
ORA-06550: line 1, column 316: PLS-00103: Encountered the symbol "/" The symbol "/" was ignored.
PLSQL example:
DECLARE
SQL1 VARCHAR2 (1500);
SQL2 VARCHAR2 (1500);
BEGIN
SQL1 := 'INSERT INTO das_html_caption VALUES (''test_test'')';
SQL2 := 'DELETE FROM das_html_caption where wording = ''test_test''';
EXECUTE IMMEDIATE SQL2;
EXECUTE IMMEDIATE SQL1;
EXECUTE IMMEDIATE SQL2;
COMMIT;
END;
/
Java:
Statement statement = dbConnection.createStatement();
ResultSet rs = null;
boolean ret = statement.execute( sql.getValue() );
is it correct error ? or i'm doing something wrong ?
Thanks
The slash is how you execute the anonymous block through an interactive environment such as SQL*Plus. If you are executing this block by a call from Java you don't need the terminating slash.
Found answer. Had to made more complcated request to google :)
As the message indicates, the compiler
doesn't want to encounter the symbol
"/", so just remove it. That simple.
Let me explain. When using sqlplus or
an SQL worksheet in sqldev, you do
well appending your PL/SQL blocks with
the slash. However, when using the
procedure editor (native to sqldev),
you'll have to remove it. Don't know
why they made this set of rules, but
until they relax them, we'll have to
obey them ;-)
http://forums.oracle.com/forums/thread.jspa?threadID=519670