I love the feature in NHibernate that shows the generated SQL. But when I pasted it into SQL Server Management Studio, I realised it's not actually valid!
Here's an example:
SELECT person0_.PersonId as PersonId1_0_, person0_.Title as Title1_0_, person0_.FirstName as FirstName1_0_, person0_.MiddleNames as MiddleNa4_1_0_, person0_.LastName as LastName1_0_ FROM Kctc.People person0_ WHERE person0_.PersonId=#p0;#p0 = 1
This is not valid because of the way the parameter p0 is specified. It needs:
DECLARE #p0 int
SET #p0 = 1
before the SELECT command.
I guess my question is: why does NHibernate not show the ACTUAL SQL it sends to the database? Why does it show this instead?
Is there something I'm missing?
Thanks
David
The command sent to SQL Server is sent is a string argument to the sp_executesql system stored procedure. The parameters list is sent as a list of parameter, value pair arguments. You can easily see this using SQL Profiler. NHibernate Profiler reformats the query into one you can cut and paste into SSMS.
Here's an example of an actual NHibernate object load as sent to SQL Server:
exec sp_executesql N'SELECT track0_.TrackId as TrackId84_0_, track0_.CreatedBy as CreatedBy84_0_, track0_.CreatedDt as CreatedDt84_0_, track0_.RevisedBy as RevisedBy84_0_, track0_.RevisedDt as RevisedDt84_0_, track0_.Name as Name84_0_, track0_.Description as Descript7_84_0_ FROM Nucleus.Track track0_ WHERE track0_.Name=#p0',N'#p0 nvarchar(8)',#p0=N'6036HPGP'
Since the query is sent as a string to sp_executesql, you may get an execution plan that is different than the one generated by executing the query directly. In some cases this can be a huge performance hit.
The SQL is sent to the driver as a prepared statement, either the SQL driver takes care of assembling the final SQL or the parameters are sent seperatly to the server in case of a server side prepared statement - neither of which hibernate has much control over, or any way of pulling back the final SQL after it's sent down to the driver.
hibernate is just showing you that parameterized SQL as well as the value of #p0 that it hands off to the SQL driver.
Related
I am making a query with ASP.NET with SqlConnection and SqlCommand. I am adding parameters to the query with the AddWithValue method, to avoid SQL injection.
I want to check the resultant query after the parameters have been included, for debug purposes. If I have "WHERE name = #myName", I want to see the query after #myName has been replaced. Is this possible?
Thank you.
Not really, because .NET never sends the complete query. The query is assembled by the database when it receives the SQL string and the parameter values.
The most you can do is log the SQL string, and log the values of the parameters you passed to it. From that you should still be able to easily infer what query was actually executed.
My project is in Visual Foxpro and I use MS SQL server 2008. When I fire sql queries in batch, some of the queries don't execute. However, no error is thrown. I haven't used BEGIN TRAN and ROLLBACK yet. What should be done ??
that all depends... You don't have any sample of your queries posted to give us an indication of possible failure. However, one thing I've had good response with from VFP to SQL is to build into a string (I prefer using TEXT/ENDTEXT for readabilty), then send that entire value to SQL. If there are any "parameter" based values that are from VFP locally, you can use "?" to indicate it will come from a variable to SQL. Then you can batch all in a single vs multiple individual queries...
vfpField = 28
vfpString = 'Smith'
text to lcSqlCmd noshow
select
YT.blah,
YT.blah2
into
#tempSqlResult
from
yourTable YT
where
YT.SomeKey = ?vfpField
select
ost.Xblah,
t.blah,
t.blah2
from
OtherSQLTable ost
join #tempSqlResult t
on ost.Xblah = t.blahKey;
drop table #tempSqlResult;
endtext
nHandle = sqlconnect( "your connection string" )
nAns = sqlexec( nHandle, lcSqlCmd, "LocalVFPCursorName" )
No I don't have error trapping in here, just to show principle and readability. I know the sample query could have easily been done via a join, but if you are working with some pre-aggregations and want to put them into temp work areas like Localized VFP cursors from a query to be used as your next step, this would work via #tempSqlResult as "#" indicates temporary table on SQL for whatever the current connection handle is.
If you want to return MULTIPLE RESULT SETs from a single SQL call, you can do that too, just add another query that doesn't have an "into #tmpSQLblah" context. Then, all instances of those result cursors will be brought back down to VFP based on the "LocalVFPCursorName" prefix. If you are returning 3 result sets, then VFP will have 3 cursors open called
LocalVFPCursorName
LocalVFPCursorName1
LocalVFPCursorName2
and will be based on the sequence of the queries in the SqlExec() call. But if you can provide more on what you ARE trying to do and their samples, we can offer more specific help too.
I'm developing an application that pulls information from a Firebird SQL database (accessed via the network) that sits behind an existing application.
To get an idea of what the most commonly used tables are in the application, I've run Wireshark while using the application to capture the SQL statements that are transmitted to the database server when the program is running.
I have no problem viewing what tables are being accessed via the application, however some of the query values passed over the network are not being displayed in the captured SQL packets. Instead these values are replaced with what I assume is a variable of some sort.
Heres a sample query:
select * from supp\x0d\x0aWHERE SUPP.ID=? /* BIND_0 */ \x0d\x0a
(I am assumming \x0d\x0a is used to denote a newline in the SQL query)
Has anyone any idea how I may be able to view the values associated with BIND_0 or /* BIND_0 */?
Any help is much appreciated.
P.S. The version of Firebird I am using is 1.5 - I understand there are syntactical differences in the SQL used in this version and more recent versions.
That /* BIND_0 */ is simply a comment (probably generated by the tool that generated the query), the placeholder is the question mark before that. In Firebird statements are - usually - first prepared by sending the query text (with or without placeholders) to the server with operation op_prepare_statement = 68 (0x44). The server then returns a description of the bind variables and the datatypes of the result set.
When the query is actually executed, the client will send all bind variables together with the execute request (usually in operation op_execute = 63 (0x3F)) in a structure called the XSQLDA.
SSIS 2008. Very simple task. I want to retrieve a System Variable and use it in an SQL INSERT. I want to retrieve the value of System:MachineName and use it in an insert statement.
Using the statement INSERT INTO MYLOG (COL1) SELECT #[System::MachineName] gives the error Error: ..failed to parse. Must declare the scalar variable "#"
Using the statements SELECT #System::MachineName or SELECT ##[System::MachineName] gives the error 'Error Incorrect systax near '::'
I am not trying to pass a parameter to the query. I have searched for a day already but couldn't find how to do this one simple thing!
Here is one way you can do this. The following sample package was created using SSIS 2008 R2 and uses SQL Server 2008 R2 as backend.
Create a sample table in your SQLServer database named dbo.PackageData
Create an SSIS package.
On the SSIS, add an OLE DB connection manager named SQLServer to connect to your database, say to an SQL Server database.
On the Control flow tab, drag and drop an Execute SQL Task
Double-click on the Execute SQL task to bring the Execute SQL Task Editor.
On the General tab of the editor, set the Connection property to your connection manager named SQLServer.
In the property SQLStatement, enter the insert statement INSERT INTO dbo.PackageData (PackageName) VALUES (?)
On the Parameter Mapping tab, click Add button, select the Package variable that you would like to use. Change the data type accordingly. This example is going to insert the PackageName into a table, so the Data Type would be VARCHAR. Set the Parameter Name to 0, which indicates the index value of the parameter. Click OK button.
Execute the package.
You will notice a new record inserted into the table. I retained the package name as Package. That's why the table
Hope that helps.
Per my comment against #ZERO's answer (repeated here as an answer so it isn't overlooked by SSIS newcomers).
The OP's question is pretty much the use case for SSIS property expressions.
To pass SSIS variables into the query string one would concatenate it into an expression set for the SqlStatementSource property:
"INSERT INTO MYLOG (COL1) SELECT " + #[System::MachineName]
This is not to suggest the accepted answer isn't a good pattern, as in general, the parameterised approach is safer (against SQL injection) and faster (on re-use) than direct query string manipulation. But for a system variable (as opposed to a user-entered string) this solution should be safe from SQL injection, and this will be roughly as fast or faster than a parameterised query if re-used (as the machine name isn't changing).
I never use it before but maybe you can check out the use of expression in Execute SQL task for that.
Or just put the whole query into an expression of a variable with evaluateAsExpression set to true. Then use OLE DB to do you insert
Along with #user756519's answer, Depending on your connection string, your variable names and SQLStatementSource Changes
I am using JDBC to call a stored procedure in MSSql 2005. I would like to have the result set make use of server side cursors to limit the amount of memory used by the client. I am able to do this easily using a simple query and setting the SelectMethod=cursor on the connection. When I put that query in a stored procedure, it appears that the entire result set is being returned as if the connection were created with SelectMethod=direct.
Is there a way to make the stored procedure call behave like a simple query.
I have tested with MS SQL JDBC driver 1.1 and 1.2. In the sample below, the difference between the two values of totalMemory is dependent on the size of the results without fetching any of the rows.
long totalMemoryUsed = java.lang.Runtime.getRuntime().totalMemory();
String sql = "{call ap_Select(?, ?, ?, ?)}";
CallableStatement cstmt = conn.prepareCall(sql,ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
cstmt.setString(1,readAlldbnames );
cstmt.setString(2,readPublicDbnames);
cstmt.setString(3, whereClause);
cstmt.setString(4, " order by key5 ");
ResultSet a_resultSet = cstmt.executeQuery();
long totalMemoryUsedAfterQuery = java.lang.Runtime.getRuntime().totalMemory();
The only thing I have found till now is to get the resultset from the stored procedure in a table, then use a serverside cursor on the table and drop the table... I wish I can find a better way than this.
Please let me know if it is possible to use serverside cursors for stored procedure calls using JDBC.
Thanks,
Sayali