BDE says "Field not found" but field exists - delphi

I have the following query to one of my database tables:
select count(*) as mycount
from mytable
where fieldone = :fieldone
and fieldtwo = :fieldtwo
Parameters are correctly loaded into the query (both of type String).
When I run this query outside the app (for instance, through the dbexplore) and replace the parameters with the actual values, I get the correct result. But when running it in the app, I get a Field 'fieldtwo' not found error, right on the Query.Open call.
Why would the BDE not find this field, when it actually exist?
Update: The following query, executed right after the first one (the one that fails), works fine in the app:
select *
from mytable
where fieldone = :fieldone
order by fieldone, fieldtwo

The best guess is that you have populated the field list in the query, this overrides any concept of the underlying fields that are in the query and is a cause of countless confusion.
Right click on the query, pick the fields editor clear all the values that are there and then choose 'add all fields' that should cause the missing field to appear once the query is executed.
I think it should auto-populate the fields if there are no defined fields when the query is executed, so you may not need to choose 'add all fields' after clearing the fields.

Whenever we come across a problem like this we tend to remove the query from the form and create it dynamically at run time... It depends how ingrained into the form it is...
E.g. If you have a data aware control looking at "fieldtwo" which tries to fetch some data when the underlying data set gets updated then it'll trigger an error like this, but it's more obvious when you've written code such
SomeEdit.Text = Query.FieldByName("fieldtwo").AsString;
That way it falls over on the relevant line instead of the open (triggering a related event)

Clear the query content using Query1.SQL.Clear; statement before opening it.
Other reason can be you are opening other database which may not have the specified field. Be sure that both the DatabaseName's in your app and dbexplore are same

I used to face porblems with BDE when i have SQLExplorer open and the app accesses the DB at the same time (but i had errors like ), try closing the Explorer it may help, if not i would build the SQL as text without the Parameters and try if it works then (if its possible in your situation).

I don't use parameters, so I'm just grabbing at straws here. I still use the BDE regularly, but am no expert. I find I shy away from more complex expressions (which yours is not!) because of the little "surprises" like this that the BDE throws at you.
Perhaps adding parentheses:
where (fieldone = :fieldone)
and (fieldtwo = :fieldtwo)
Or, single or double quote signs (this probably will make it worse?)
where (fieldon = ":fieldone")
and (fieldtwo = ":fieldtwo")
Or, to explore the problem, remove the "and fieldtwo = :fieldtwo" line and see if it runs.
Would it be possible for you to do your own parameter substitution with a StringReplace as in
Query1.SQL.Text := StringReplace(Query1.SQL.Text, ":fieldone", "MyVarName",[rfReplaceAll ]);

If you are creating a ClienDataSet in memory by the Create DataSet method, you should check the TFieldDefs property, which must have a different field name or not created

I was having a weird but small problem, I'll post in case it will help someone in some day.
uRegPeople.pas
with frmEditPerson do
begin
PersonID := qryPerson.FieldByName(ID).AsInteger;
...
end;
I had qryPerson both in frmRegPeople and in frmEditPerson, by using with I was referencing to frmEditPerson.qryPerson, however I wanted to reference to frmRegPeople.qryPerson. Then I need to change to the following code.
with frmEditPerson do
begin
PersonID := Self.qryPerson.FieldByName(ID).AsInteger;
...
end;
// Explanation
// qryPerson --> frmEditPerson.qryPerson;
// Self.qryPerson --> frmRegPeople.qryPerson;

Related

SQL-Server Transaction Blocking Mystery

I have a .Net app used for form processing which deletes/updates/inserts data across three different SQL Server 2012 databases. When the application runs, it opens a data context and then a transaction within that context for each form that needs to be processed (this runs every minute, so it's usually no more than one form at a time). A bunch of stuff happens within this transaction -- including multiple stored proc calls.
So here's the problem:
We have servers set up with what I'm told are the exact same specs (although I'm dubious :)). One is used for development work; the other for client testing. In our development environment, the processing runs without problems; but on the client testing site, it hangs every time. And I'm pulling my hair out trying to determine why.
In the following TSQL code, it is the insert into the Param table that is failing. The Param table is essentially the same as the Method table, except for the column names. Both inserts have similar foreign key relationships to the Form table, and both insert int values into the ID column.
When I run SQL Server Profiler, I'm told there's a lock on the FormDB which is not allowing the insert. However, I can alter the select statement for the Param insert and it works. I've altered in the following ways, all of which "work" in the sense that they do not cause the blocking issue:
Replaced the Param select with the Method select while keeping the insert to Param.(exact same column defs as param select)
Replaced #newKey with a valid integer for an existing form.
Removed the "from" portion of the Param select and hardcoded a single int value for the paramID (ie select #newKey, 1, #modifyDate, #modifyUser)
I feel like I'm losing my mind, because I just can't see why it's not working. The insert only seems to fail when three things are all in the select statement in combination -- #newKey, ParamID, and the from statement.
I've ensured each sproc has SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED and have used with nolock where necessary.
Why can I successfully insert into the Param table via the three scenarios above, but fail for the Param insert in the code that follows? Why would I not receive the same lock message in the profiler? There are about 5 other inserts in this procedure which follow the same pattern. All of them work with no problem.
Any ideas? Thanks.
USE [PROD]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[HELPSPROC]
#oldKey int
AS
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
declare #newKey int
, #spKey int
, #modifyDate datetime = getdate()
, #modifyUser varchar(30) = 'User'
/*
a bunch of stuff happens here, including setting the #spKey value.
this all happening correctly -- we have a valid integer value when we go into the next part
*/
---------------FORM---------------
INSERT INTO FormDB.dbo.Form
(formtype, formstatus, modifydate, modifyuser)
Select
'TestFormType', 'DRAFT', #modifyDate, #modifyUser
From FormDB2.dbo.Form f
Where f.Pkey = #oldKey
--grab the new int identifier -- works
set #newKey = (select scope_identity())
/*
stuff happens here. all is good in this part
*/
---------------Param---------------
INSERT INTO FormDB.dbo.Param
(FormKey, ParamID, ModifyDate, ModifyUser)
select #newKey, p.ParamID, #modifyDate, #modifyUser
from PROD.dbo.Table1 apd
inner join PROD.dbo.ParameterTable p
on apd.TableTwoKey = p.TableTwoKey
where apd.PKey = #spKey
---------------Method---------------
INSERT INTO FormDB.dbo.Method
(FormKey, MethodID, ModifyDate, ModifyUser)
select #newKey, r.MethodID, #modifyDate, #modifyUser
from PROD.dbo.Table1 apd
inner join PROD.dbo.MethodTable r
on apd.TableTwoKey = r.TableTwoKey
where apd.PKey = #spKey
/*
one more insert ...
*/
RETURN 1
END
GO
I still don't understand the why of this problem, but I found a solution.
There are a lot of things happening in the vb.net code for this process: multiple linq-to-sql inserts/deletes/updates across three separate databases, as well as two separate stored procedures calls. To add to that confusion, there are separate contexts declared for each db, each with its own transaction. In short, a bunch of moving parts.
The second stored proc call was conditional, based on certain values for the processing form. I just took that call out of the vb.net code, and placed the conditional logic and stored proc call within the first proc. That solved it. The second stored proc was called directly after the first anyway -- pending conditions -- so all is good.
Problem solved -- but if anybody can explain why this was occurring, I'd be grateful. Thanks!

FireDAC - Show SQL after Macro Expantion

I am trying to use Macros in FireDAC to Preprocess my SQL Queries. I have a TADQuery object on a Data Module with the SQL set to something like:
Select * from MyTable
join OtherTable on MyTable.Key = OtherTable.Key
&Where
Then in my code I do this:
WhereClause = 'stuff based on my form';
Query.MacroByName('Where').AsRaw := WhereClause;
Query.Open;
This has worked great for complicated queries because it lets me make sure my fields and join conditions are correct using the SQL Property editor.
My problem is when the SQL statements ends up invalid because of my where clause. Is there any way to see the SQL after pre-processing that is going to be executed? Right now I am catching the FireDac errors and showing the SQL that is on EADDBEngineException object. However that is still showing my original SQL with the macros. If I can't get to it after the error happens is there anyway to force the Macro replacement to take place so I can look at the SQL in the debugger to help me see what is wrong.
If it matters I am connecting to a MS Access database with the goal of moving to SQL Server in the near future.
Apart from using Text property, to monitor what SQL is actually going to the database engine, consider using the "FDMonitor" FireDAC utility. According to the DokWiki pages (below):
drop a TFDMoniRemoteClientLink component on your form,
Set its Tracing property to True,
Add the MonitorBy=Xxx connection definition parameter to your existing FDConnection component. You can do this in the IDE object inspector, by selecting your FDConnection component, expanding the Params property, and setting MonitorBy to mbRemote.
Note that the TFDMoniXxxxClientLink should come before TFDConnection in the data module or form creation order, so adjust this by right clicking on the form or data module, then Creation Order, and moving the TFDMoni.. component above the FDConnection.
Also, it's helpful in the options of the TFDMoniXxxxClientLink, to disable most of the events being recorded, otherwise all the data returned is also shown in the FireDAC monitor. Expand the EventKinds property, and turn all the event kinds off, except for perhaps ekConnConnect, ekConnPrepare, and ekCmdExecute.
Then open the FireDAC Monitor from the IDE, (Tools > FireDAC Monitor). Start your app only once the monitor is running. Double click on a trace event (in the Trace Output tab), and you will see the actual SQL sent to the database in the bottom pane.
It also seems likely that adding the EventType of ekConnPrepare as mentioned above, would show you when the query's Prepare is called, but I haven't played enough with it say for sure.
Please see the following pages on the DocWiki for more information:
Overview: FDMonitor
How to: Tracing and Monitoring (FireDAC)
Other FireDAC utilities: Utilities (FireDAC)
(Just to remove this question from list of unanswered questions)
From comments:
Well, I've roughly checked what's happening there and I'm still not
sure if calling Prepare (which is useless for you as I get) is the
minimal requirement to trigger that preprocessing. Though, the
preprocessed SQL, the one which is sent to the DBMS you can access
through the Text property (quite uncommon name for such property). – TLama Feb
21 '14 at 8:18

Complex T-SQL script executed via TADOQuery is firing "Multiple-step OLE DB operation generated errors."

I have a very large block of SQL that I am trying to execute inside of Delphi, against a Microsoft SQL Database. I am getting this:
Multiple-step OLE DB operation generated errors.
Check each OLE DB status value, if available. No work was done.
The script has multiple sql IF statements followed by BEGIN and END blocks with invocations of stored procedures, declaration of variables, and EXEC inside that. Finally it returns some of the variable values by SELECT #Variable1 AsName1,#Variable2 AsName2....
The above multi-step error is coming in as an OLEException from ADO, not from the Delphi code, and happens after all the SQL exec-stored-procedure have occurred, and therefore I suspect it's firing this OLE exception when it reaches the final stage which SELECT #Variable1 AsName1,... to get back a few variable values for my program to see them.
I know about this retired/deprecated MS KB article, and this is unfortunately not my actual issue:
http://support.microsoft.com/kb/269495
In short that KB article says to fix a registry key and remove "Persist Security Info" from the connection string. That's not my problem. I'm asking this question because I found the answer already and I think that someone else who gets stuck here might not want to waste several hours finding potential issues when there are several that I have found after searching for solutions for several hours. Anyone who wants to add another answer with different options, is fine, and I'll select yours if it's reproducible, and if necessary I'll turn this one into a Community Wiki because there could be a dozen obscure causes for this "ADO recordset is in a bad mood and is unhappy with your T-SQL" exception.
I have found several potential causes that are listed in various sources of documentation. The original KB article in the question suggests removing the 'Persist Security Info' from my ADO connection string, however in a standalone test in an application with just a TADOConnection and a single TADOQuery, the presence or absence of Persist Security Info had no effect, nor did explicitly setting it True or False.
What DID fix it was removing this CursorType declaration:
CursorType=ctKeyset
What I have learned is that bidirectional ADO datasets are fine for SELECT * FROM TABLE in ADO but are not so fine for complex SQL scripts.
Potential source of this error is updating char field with large value.
Example: Form has edit box with max length property set to 20 characters and Oracle database table has field defined as char(10).
Updating with 10 characters (or less) will work fine while updating with more then 10 characters will cause 'Multiple step...' error on ADOQuerry.UpdateBatch().
You also have to know that CHAR will allways have 20 characters. Consider Trimming value in edit box. CHAR behaves different than VARCHAR2 type.
If you have a query with parameter ,check the number of parameters in the query is matched with script...!

Access 2010 form not displaying query

I'm sure this is an easy fix but I can't seem to find it. I just have a form, that will be a subform of another, that needs to display the results of a query.
The query is simple enough, just displays all fields of records that fall between specified dates. The query works great, but when I attach it to the form as its record source it doesn't display the data. I can see the correct amount of record selectors so I know its understanding the query but its as if all fields are hidden!
I have also tried building a query to the forms record source that was simply Select query.* From query. Oddly I have had this working before but I had to specify every field. What I mean is:
Select title From query
Select type From query
Select date From query
...
And so on for all the fields but this seems foolish, can anyone think of what I may be doing wrong?
Thanks in advance!
Edit, forgot to mention I also tried the foolish solution that I mentioned above and it didn't work so its definitely some issue that I'm not seeing, some property that's probably not appropriately set
#sshekhar well its not really code at the moment I'm using Access 2010. I have a form that needs to display a subform that executes this query of displaying records that have a data field that fall between dates specified by the user. The query works and displays the correct records, but the form that it is attached to only shows the record selectors and all the fields appear to be "hidden." I thought it may be one of the form's properties set incorrectly but I checked on the test form from another database that I used and each have what appears to be identical settings. So I'm at a loss!
So it turns out even though I using a query that holds all the fields it will not display the content unless you go to the Add Existing Fields and add all the the fields you want to see. This seems really silly especially when the results in the query but at least its working now.
I had this problem and discovered that having the property DataEntry set to YES will only display new records. From Microsoft Help:
You can use the DataEntry property to specify whether a bound form
opens to allow data entry only. The Data Entry property doesn't
determine whether records can be added; it only determines whether
existing records are displayed. Read/write Boolean.

Site column does not get deleted

I have a Site column which i delete programatically using the following code. I have already removed all references to the field previously. However, even if there is not error, it goes to fieldtodelete.Delete() and steps through the next line. However, when i check the Site Column collection using SPM2007 or via the UI the site column is still there.
Dim fieldtodelete As SPField
Try
fieldtodelete = site.RootWeb.Fields.GetFieldByInternalName(name)
'site.RootWeb.Fields.GetFieldByInternalName(name)
fieldtodelete.Delete()
Catch ex As Exception
Console.WriteLine("Field: {0} was not deleted", name)
Return 0
End Try
Any ideas on why sharepoint does this? Also, there are 2 fields with the same name, i am not sure if this has a direct effect on this. I want to delete both.
Thanks
Since there are 2 fields with the same name, their internal names are likely different than the Name. Are you sure the line
fieldtodelete = site.RootWeb.Fields.GetFieldByInternalName(name)
is actually returning a valid SPField? If not, you will need to find the internal names of the fields, which don't necessarily match up to the Names.
EDIT: Since you said that you are getting the fields back, I realized you aren't calling site.RootWeb.Update() after deleting the field. That should fix the issue.

Resources