Reputation: 7028
I am generating a multiple insert records query in C# and trying to execute in FireBird.
When I am running it on FlameRobin it works so well. But When I am running it via C# it throws exception.
SET TERM ^ ; INSERT INTO COUNTRY1 SELECT '2', 'two ' FROM RDB$DATABASE UNION ALL SELECT '4', 'four' FROM RDB$DATABASE UNION ALL SELECT '5', 'five' FROM RDB$DATABASE; ^ SET TERM ; ^
Exception in C# code is
{"Dynamic SQL Error\r\nSQL error code = -104\r\nToken unknown - line 1, char 5\r\nTERM"}
C# Code is
string sQuery = "SET TERM ^ ; INSERT INTO COUNTRY1 SELECT '2', 'two ' FROM RDB$DATABASE UNION ALL SELECT '4', 'four' FROM RDB$DATABASE UNION ALL SELECT '5', 'five' FROM RDB$DATABASE; ^ SET TERM ; ^ ";
SqlHelper.ExecuteNonQuery(SQLHelp.Connectionstring, CommandType.Text, sQuery);
Any idea whats wrong I am doing here? Thanks
Upvotes: 0
Views: 1761
Reputation: 108941
Your query does not conform to the Firebird syntax. Drivers can only execute a single statement at a time (be aware that an EXECUTE BLOCK
is considered to be a single statement).
You should not use SET TERM
, that is an artifact of the ISQL tool (and some other query tools like FlameRobin) and is not actually part of the Firebird SQL language.
Nor should you include ;
in a query. Those are only valid in 1) PSQL (stored procedures, triggers and inside EXECUTE BLOCK
) and 2) once again in tools like ISQL to separate (end) statements.
So using the following query on its own should be sufficient:
INSERT INTO COUNTRY1 SELECT '2', 'two ' FROM RDB$DATABASE UNION ALL SELECT '4', 'four' FROM RDB$DATABASE UNION ALL SELECT '5', 'five' FROM RDB$DATABASE
EDIT
As I commented, maybe the parser doesn't understand UNION
when combined with an INSERT ... SELECT
.
Using a sub-select will probably work:
INSERT INTO COUNTRY1
SELECT column1, column2 FROM (
SELECT '2' AS column1, 'two ' AS column2 FROM RDB$DATABASE
UNION ALL SELECT '4', 'four' FROM RDB$DATABASE
UNION ALL SELECT '5', 'five' FROM RDB$DATABASE
)
EDIT 2
I just tested it with the the code below and it works: the expected rows are inserted:
static void Main(string[] args)
{
var constrBuilder = new FbConnectionStringBuilder();
constrBuilder.DataSource = "localhost";
constrBuilder.Database = @"D:\data\db\testdatabase.fdb";
constrBuilder.UserID = "sysdba";
constrBuilder.Password = "masterkey";
string constr = constrBuilder.ToString();
using (var con = new FbConnection(constr))
{
con.Open();
using (var trans = con.BeginTransaction())
{
var cmd = new FbCommand();
cmd.CommandText = "INSERT INTO COUNTRY1 SELECT '2', 'two ' FROM RDB$DATABASE UNION ALL SELECT '4', 'four' FROM RDB$DATABASE UNION ALL SELECT '5', 'five' FROM RDB$DATABASE";
cmd.Connection = con;
cmd.Transaction = trans;
cmd.ExecuteNonQuery();
trans.Commit();
}
}
}
Upvotes: 1
Reputation: 17203
The set term
statements you're including are not part of Firebird SQL language, but is a kind of interpreter configuration instruction firstly introduced in isql, which is the command line client for Firebird.
Look at your script this way:
SET TERM ^ ;
INSERT INTO COUNTRY1
SELECT '2', 'two ' FROM RDB$DATABASE
UNION ALL SELECT '4', 'four' FROM RDB$DATABASE
UNION ALL SELECT '5', 'five' FROM RDB$DATABASE; ^
SET TERM ; ^
The engine doesn't know and can't process the set term
statements.
FlameRobin and other clients add support for the set term
statement for compatibility: to allow running SQL scripts written for isql, or because they lacks a fully SQL parser and still needs to properly recognize where a statement ends when a script includes semi-colons. But all this clients, once a statement is delimited inside a script, doesn't send the set term
to the engine, just ignores it.
You have to do the same: remove the set term
statements and send the unique other statement you have, like this:
INSERT INTO COUNTRY1
SELECT '2', 'two ' FROM RDB$DATABASE
UNION ALL SELECT '4', 'four' FROM RDB$DATABASE
UNION ALL SELECT '5', 'five' FROM RDB$DATABASE
Be aware you must also remove the ;
Upvotes: 2