When I tried to use FireDAC FDQuery with MySQL database I got the following error:
Cannot perform this operation on an open dataset.
query.Open(....my connection string to MySQL....);
try
query.ExecSql;
finally
query.Close;
I filled the FDQuery by double-clicking on the icon on the form. I also
connected to the database to test it. It gave back the results correctly.
I would like to use it from code, but it doesn't work, so
I debugged it. I always get to the breakpoint: query.Close;
You can't call Open and ExecSQL on the same SQL, because they do different things.
Use Open when the query will return a result set, which means for a SELECT. Use ExecSQL when the query does not return a result set, which means for an INSERT, DELETE or UPDATE.
I can't tell you which one applies to your situation, because you failed to include your SQL in your post.
I don't know about FireDAC specifically, but in general with these kind of database components, for queries not returning a result set, thus suitable for ExecSQL, you would want to use ExecSQL on the Connection object, in this case TFDConnection. (Which would presumably be the Connection object that your FDQuery object is connected to.)
http://docwiki.embarcadero.com/RADStudio/Rio/en/Executing_Commands_(FireDAC)
Apparently there is an ExecSQL method on TFDCustomQuery, but I'm not sure why you would use that, and as you discovered, it doesn't work if the query is already in use.
I have a poll enrich which enriches a POJO with the result of an SQL query (from a MySQL database). It currently gets the brand from the POJO and then gets the name from the order matching the brand. I had to add quotes around the ${body.getBrand}, else the query would look for a column with the brand name instead of using the value. Currently it looks like this:
<pollEnrich id="_enrich1" strategyRef="merge" timeout="5000">
<simple>sql:SELECT name FROM orders WHERE brand= '${body.getBrand}'</simple>
</pollEnrich>
I want to change it because I'll probably need to create more sql queries and the current version does not work if the value contains quotes and thus is vulnerable to sql injection.
I thought prepared statements would do the trick and wanted to use a named parameter but I do not seem to be able to set the value of the parameter.
I have tried many different things like for example setting a header and change the query to have a named parameter:
<setHeader headerName="brand" id="brand">
<simple>${body.getBrand}</simple>
</setHeader>
<pollEnrich id="_enrich1" strategyRef="merge" timeout="5000">
<simple>sql:SELECT name FROM orders WHERE brand= :#brand</simple>
</pollEnrich>
but I keep getting
PreparedStatementCallback; bad SQL grammar [SELECT name FROM orders WHERE brand= ?]; nested exception is java.sql.SQLException: No value specified for parameter 1
I have also tried setting the useMessageBodyForSql option to true (since this seemed like something that might help?) but nothing I have tried seemed to work.
I have seen a lot of examples/solutions for people setting the routes with java, but I assume there must also be a solution for the blueprint xml?
If anyone got any suggestion or example that would be great.
In Camel version < 2.16, pollEnrich doesn't have access to the original exchange and therefore cannot read your header, hence the exception. This is documented here: http://camel.apache.org/content-enricher.html
Guessing from your example, a normal enrich should work too and it has access to the original exchange. Try changing 'pollEnrich' to 'enrich'.
I'm trying to build a Data Integration job uses pass through to extract data from a view in a MySQL database.
Wev'e been using pass through a lot in the project, mostly extracting data from Redshift,
however with MySQL I was not able to do make it work properly.
It keeps complaining a table is missing even though when pass through is off, view is found and data is extracted...
tried every trick I know, starting from enabling case-sensitive DBMS object names, to manually remove single/double quotes from the statement just in case MySQL confuses confuses it with something else...
No luck.
ODBC driver is [MySQL][ODBC 5.3(a) Driver][mysqld-5.5.53].
Ran on a Windows environment.
Any idea how to solve this?
Thank you in advance.
EDIT
So, first of all, one correction (even though not that important - I extract from a view, not a table).
This is the code generated by SAS Create Table transformation, pass through enabled. I only put an asterisk instead of the full list of columns:
proc sql;
connect to ODBC
(
READBUFF=10000 DATASRC="cmp.web_api" AUTHDOMAIN="MYSQL_CMP_Auth"
);
create table work."W7ZZZKOC"n as
select
*
from connection to ODBC
(
select
V_BI_ACCOUNT.ACCOUNT_NAME,
V_BI_ACCOUNT.ACQUISITION_SOURCE__C,
V_BI_ACCOUNT.ZUORA__ACTIVE__C,
V_BI_ACCOUNT.ADDRESS_LINE_1__C,
V_BI_ACCOUNT.ADDRESS_LINE_2__C,
V_BI_ACCOUNT.ADDRESS_LINE_3__C,
V_BI_ACCOUNT.AGREEMENT_DATE,
V_BI_ACCOUNT.AGREEMENT_LEGAL_CLAUSE_1__C,
V_BI_ACCOUNT.AGREEMENT_LEGAL_CLAUSE_2__C,
V_BI_ACCOUNT.PERSONBIRTHDATE,
V_BI_ACCOUNT.BLOCKED_REASON__C,
V_BI_ACCOUNT.BRAND__C,
V_BI_ACCOUNT.CPN__C,
V_BI_ACCOUNT.ACCCREATEDBYID,
V_BI_ACCOUNT.ACCCREATEDDATE,
V_BI_ACCOUNT.CURRENCY_PREFERENCE__C,
V_BI_ACCOUNT.CUSTOMER_FULL_NAME__PC,
V_BI_ACCOUNT.ACCOUNTID,
V_BI_ACCOUNT.ZUORA__CUSTOMERPRIORITY__C,
V_BI_ACCOUNT.DELIVERY_SALUTATION__C,
V_BI_ACCOUNT.DISPLAY_NAME,
V_BI_ACCOUNT.PERSONEMAIL,
V_BI_ACCOUNT.EMAILKEY__C,
V_BI_ACCOUNT.FACEBOOKKEY,
V_BI_ACCOUNT.FIRSTNAME,
V_BI_ACCOUNT.GENDER__C,
V_BI_ACCOUNT.PHONE,
V_BI_ACCOUNT.ACCLASTACTIVITYDATE,
V_BI_ACCOUNT.ACCLASTMODIFIEDDATE,
V_BI_ACCOUNT.LASTNAME,
V_BI_ACCOUNT.OTHER_EMAIL__C,
V_BI_ACCOUNT.PI_TYPE__C,
V_BI_ACCOUNT.ACCPARENTID,
V_BI_ACCOUNT.POSTCODE__C,
V_BI_ACCOUNT.PRIMARY_ACCOUNT_OF_THIS_CUSTOMER,
V_BI_ACCOUNT.ACCPRIMARY__C,
V_BI_ACCOUNT.ACCREASON_FOR_STATUS__C,
V_BI_ACCOUNT.ZUORA__SLA__C,
V_BI_ACCOUNT.ZUORA__SLASERIALNUMBER__C,
V_BI_ACCOUNT.SALUTATION,
V_BI_ACCOUNT.ACCSYSTEMMODSTAMP,
V_BI_ACCOUNT.PERSONTITLE,
V_BI_ACCOUNT.ZUORA__UPSELLOPPORTUNITY__C,
V_BI_ACCOUNT.X_CODE__C,
V_BI_ACCOUNT.ZUORA__ACCOUNT_ID__C,
V_BI_ACCOUNT.ZUORA__PAYMENTMETHODID__C,
V_BI_ACCOUNT.CITY,
V_BI_ACCOUNT.ORIGINAL_CREATED_DATE,
V_BI_ACCOUNT.SOURCE_SYSTEM_ID,
V_BI_ACCOUNT.STATUS,
V_BI_ACCOUNT.ZUORA__CONTACT_ID,
V_BI_ACCOUNT.ACCISDELETED,
V_BI_ACCOUNT.BILLING_ACCOUNT_NAME,
V_BI_ACCOUNT.ACZCREATEDDATE,
V_BI_ACCOUNT.ACZSYSTEMMODSTAMP,
V_BI_ACCOUNT.ACZLASTACTIVITYDATE,
V_BI_ACCOUNT.ZUORA__ACCOUNT__C,
V_BI_ACCOUNT.ZUORA__ACCOUNTNUMBER__C,
V_BI_ACCOUNT.ZUORA__AUTOPAY__C,
V_BI_ACCOUNT.ZUORA__BALANCE__C,
V_BI_ACCOUNT.ZUORA__CREDITCARDEXPIRATION__C,
V_BI_ACCOUNT.ZUORA__CURRENCY__C,
V_BI_ACCOUNT.ZUORA__MRR__C,
V_BI_ACCOUNT.ZUORA__PAYMENTTERM__C,
V_BI_ACCOUNT.ZUORA__PURCHASEORDERNUMBER__C,
V_BI_ACCOUNT.ZUORA__LASTINVOICEDATE__C,
V_BI_ACCOUNT.COUNTRY_NAME,
V_BI_ACCOUNT.COUNTRY_CODE,
V_BI_ACCOUNT.FAVOURITE_FOOTBALL_CLUB,
V_BI_ACCOUNT.COUNTY
from
web_api.V_BI_ACCOUNT as V_BI_ACCOUNT
);
%rcSet(&sqlrc);
disconnect from ODBC;
quit;
And again, when I extract data without pass through - works successfully,
I found out the problem was a column name exceeds 32 positions.
As SAS supports up column names up to 32,
the query fails to find PRIMARY_ACCOUNT_OF_THIS_CUSTOMER as the original column name is PRIMARY_ACCOUNT_OF_THIS_CUSTOMER__C.
EDIT
One more thing I found out is, MySQL doesn't like specifying schema name nor aliases.
Therefore,
From clause to only specify table name i.e : 'from v_bi_account' rather than 'web_api.v_bi_account'
and do not use aliases i.e use 'from v_bi_account' rather than 'from v_bi_account as v_bi_account'
Thank you guys so much for your help.
I want to parse the content of xml files and create queries to insert/update some of the xml content in a database.
So far I am able to generate the SQL queries in a processor, populate the body with them, then I would like to run them with the SQL component.
First please let me know if this is not the recommended way to do.
(for instance I feel like the SQL component is meant to run only 1 query).
...
.process(new XmlToSqlProcessor())
.to("sql:${in.body}?dataSource=dataSource")
Doesn't work, ${in.body} is not replaced by its content (meaning the set of queries generated in the processor):
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '${in.body}' at line 1
Should I do all the work in the processor (I wanted to avoid all the database boilerplate though), or maybe use the JDBC component?
If yes can you confirm that the SQL component can only run 1 query and can not parse Simple Expression Language? (I also tried :#${body} that I saw there https://issues.apache.org/jira/browse/CAMEL-7455 but as expected it's considered as a param, not a whole query)
Thanks!
EDIT: after more reading it seems like the SQL component and the JDBC component as well can execute only 1 query. So, having my own processor is apparently the only choice... let me know if I am wrong ;-)
You are right, sql component will execute only 1 query and will not evaluate ${in.body}. You miss two concepts in your route:
Splitter (http://camel.apache.org/splitter.html)
RecipientList
(http://camel.apache.org/recipient-list.html)
Try something like:
...
.process(new XmlToSqlProcessor())
.split().body()
.recipientList(simple("sql:${in.body}?dataSource=dataSource"))
I want to create a stored procedure to do some combined keyword search using CONTAINS,something like below:
SELECT theContent
FROM FtsTest
WHERE CONTAINS
(theContent,
' FORMSOF (INFLECTIONAL, keyword1) AND FORMSOF (INFLECTIONAL, keyword2)');
and he number of keywords may vary, so I tried to pass the whole 'FORMSOF... AND FORMSOF.....'clause as a parameter,declaring the parameter as nvarchar(max),but it won't let me do it,saying The argument type "nvarchar(max)" is invalid for argument 2 of "CONTAINS".
So, is there any way to make it work with the sp?
Thanks!
Just declare argument 2 of contains as nvarchar(4000) instead of nvarchar(max) and it will work.
See the difference here: https://msdn.microsoft.com/en-us/library/ms186939.aspx
2 GB is a bit too much for the search expression.
this seems stupid,but using nvarchar(500) instead of nvarchar(max), Sql Server cheerfully accepts it and works just fine.
Still trying to gain some insight on sp_executesql,thanks.
You could build it dynamically and pass in the keywords as parameters. Executing with sp_executesql allows you to take advantage of the query plan cache, as described in the answers to this question:
Alternative to executing dynamic sql
You may need to watch out for this issue, though, that relates to parameter sniffing and full text queries:
http://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=510118