I set up an external content FTS4 virtual table in my app to allow full text search of an existing database. I also set up triggers similar to the documentation, so when my main content table is updated the FTS table gets new entries as well.
CREATE TRIGGER t2_bu BEFORE UPDATE ON t2 BEGIN
DELETE FROM t3 WHERE docid=old.rowid;
END;
CREATE TRIGGER t2_bd BEFORE DELETE ON t2 BEGIN
DELETE FROM t3 WHERE docid=old.rowid;
END;
CREATE TRIGGER t2_au AFTER UPDATE ON t2 BEGIN
INSERT INTO t3(docid, b, c) VALUES(new.rowid, new.b, new.c);
END;
CREATE TRIGGER t2_ai AFTER INSERT ON t2 BEGIN
INSERT INTO t3(docid, b, c) VALUES(new.rowid, new.b, new.c);
END;
The problem is that the triggers don't seem to actually update the index. I did a simple select * from the fts_transactions table and I see the new entries with correct text and rowid, but when actually searching they don't show up. To get them to show up I have to do a full rebuild like this:
INSERT INTO fts_transactions(fts_transactions) VALUES('rebuild');
Is this how it is supposed to work? I would have figured that the insert/update/delete into the FTS table would modify the index and not require me to rebuild it every time. After rebuilding the new entries show up just fine.
If that is the case, then is it okay to just add the rebuild command to the triggers? I am just worried that adding a new item will become slow once it has to rebuild the index with a few thousand entries on and older device...it seems that there should be a better way.
Is this how it is supposed to work?
yes, I put this line in each Triger
INSERT INTO fts_transactions(fts_transactions) VALUES('rebuild');
Related
When we enter tab without completing the query with ;, what exactly happens? Does it affect the database if we e.g. perform an update like this?
psql> update students set where roll_no=23 (entered tab)
As result, the actual result of the query appears.
When we do the following:
psql> update students set where roll_no=23
When used inside begin .. commit and without begin ... commit
Result is a warning and the command is not affecting the database.
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!
Iam trying to delete all records in my FDTable component using ,
mytable.Delete;
but no record is getting deleted.
can any one suggest me a way to delete all records in a FdTable.
EDIT
i modified it in this way,
for i := mytable.RecordCount - 1 downto 0 do
begin
mytable.Delete;
end;
mytable.Refresh;
but it is taking lot of time because there a lot rows in my fdtable.
Try
MyTable.EmptyDataSet;
There may be a bit more to do than that, but you don't say how you are populating MyTable in the first place.
Remove all the records in the underlying database table (the best way to do that will depend on the database) and call refresh just once.
If you must do it via TFdTable, use BeginBatch, do your deletes (without refresh), EndBatch and only then Refresh.
mytable.BeginBatch;
for i := mytable.RecordCount - 1 downto 0 do
begin
mytable.Delete;
end;
mytable.EndBatch;
mytable.Refresh;
I would suggest you use a stored procedure for the job and not SQL from your application. Stored procedures are simple to make and blazing fast because they operate directly on the server.
Just create a stored procedure for your table;
sp_deleteall
and do in it a single line of sql:
delete from mytable
From your application,drop a TFDStoredProc on the form, link it to your stored procedure on the server and just call on the procedure
`
sp_deleteall.ExecProc;
To know how many records were deleted just call, after the procedure execution :
ShowMessage(IntToStr(sp_deleteall.RowsAffected) + ' records were deleted.');
Try it ...
Try
as doing delete for all the rows would hamper the performance.
If that does not work then why don you create the dataset runtime and then free the object.
Form fastest to slowest. First two are commands you execute server side.
Close the table and do a SQL DDL command TRUNCATE TABLENAME; and then reopen. This requires exclusive access to the table.
Use a SQL DML command DELETE FROM TABLENAME;. This does not require exclusive access.
Use a loop client side. A lot slower and triggers a lot of events client side.
all you need to do for delete all records on a FDMemTable is
MyTable.Active := False;
I am creating a temp table in SQL and then adding a new field to it. It seems Firedac is caching the field list for this temp table.
The following code gives me "FDQuery5: Field 'Available' not found."
FDQuery5.Connection := FDConnection1;
FDConnection1.ExecSQL('Select StockNo into #Temp from Stock');
FDQuery5.SQL.Text := 'Select * From #Temp';
FDQuery5.open;
FDConnection1.ExecSQL('Alter Table #Temp add Available Char(1)');
FDQuery5.Close;
FDQuery5.open;
ShowMessage(FDQuery5.FieldByName('Available').AsString);
using XE5 with Firedac.
I have tried Connection.RefreshMetadataCache and I have removed fiMeta from FetchOptions.Cache.
I can get Firedac to recognise the new field if I modify the SQL.Text. This is undesirable as my application will need modifying in quite a few places.
The query remains prepared after you call FDQuery5.Close. That means, it caches also result set structure. To prepare the query replace FDQuery5.Close with FDQuery5.Disconnect.
Using Advantage Server 9x, I am trying to create a copy of a DBF/CDX table structure using the following code:
table1.AdsCopyTableStructure(d.AdsConnectionTemp.connectPath+'table.dbf');
The table that is created is of the type ttAdsADT, even though the original table is ttAdsCDX.
I tried using AdsConvertTable on the resulting table, but it pops an exception complaining that the operation cannot be done on free tables.
Any way to do this?
I was not able to get this function to work, but came up with a work around by using the following code:
t:=TAdsTable.create(nil);
try
t.AdsTableOptions.AdsFilterOptions:=RESPECT_WHEN_COUNTING;
t.open;
t.AdsSetAOF('keyval=-1'); // gives an empty result
t.AdsCopyTable('c:\somewhere\emlt.dat');
t.close;
finally
freeAndNil(t);
end;
You have a couple of options.
If you don't mind having a single record you can always do
Select top 1 * into mynewtable.dbf from oldtable
which is quick
A second option would be to do your first method, saving it to an adt file (which is the default) then open THAT table and use ADSConvertTable function to create the DBF.
ADTTable.ADSTableConvert('dbftable.dbf',ttADSCDX);