Building SQLIte3 wiuth debug options fails on UBUNTU
(1) By anonymous on 2020-06-23 06:18:08 [link] [source]
Dear forum member, I a script to build a debug option of SQLITE3 so I can use .selecttrace and .wheretrace. The result is: .selecttrace will result in a segment fault when I use Linux Mint. UBUNTU will NOT compile a DEBUG version and .selecttrace or .whjeretrace WILL NOT WORK. P.S. is there a method to reset my password to allow me to login??? Here is the script with all the options I am using. Feel free to modify it so other users can build a custom SQLite3 version. #! /bin/bash usage="Usage : '$0 ' [-hbd]" if [[ $1 =~ (-[bdh]) ]]; then echo "--------------" else echo "Not a valid option is given!" echo $Usage exit 1 fi while getopts "bdh" opt; do case ${opt} in h ) echo $usage echo "Options:" echo " -b Compile without debug options" echo " -d Compile with debug options" echo " -h This menu for help" exit 0 ;; b ) echo "Building SQLite3 without debug options" export CFLAGS="-fPIC \ -DSQLITE_ENABLE_FTS3 \ -DSQLITE_ENABLE_FTS3_PARENTHESIS \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_FTS5 \ -DSQLITE_ENABLE_JSON1 \ -DSQLITE_ENABLE_LOAD_EXTENSION \ -DSQLITE_ENABLE_RTREE \ -DSQLITE_ENABLE_STAT4 \ -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT \ -DSQLITE_TEMP_STORE3 \ -DSQLITE_USE_URI \ -O2 " ;; d ) echo "Bulding SQLite3 with debug options" export SQLITE3_CFLAGS="-fPIC \ -DSQLITE_ENABLE_FTS3 \ -DSQLITE_ENABLE_FTS3_PARENTHESIS \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_FTS5 \ -DSQLITE_ENABLE_JSON1 \ -DSQLITE_ENABLE_LOAD_EXTENSION \ -DSQLITE_ENABLE_RTREE \ -DSQLITE_ENABLE_STAT4 \ -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT \ -DSQLITE_TEMP_STORE3 \ -DSQLITE_USE_URI \ -DSQLITE_DEBUG \ -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ -DSQLITE_ENABLE_SELECTTRACE \ -DSQLITE_ENABLE_WHERETRACE \ -O2" ;; * ) echo "Invalid Option: -$OPTARG" echo $usage >&2 exit 1 ;; esac done LIBS="-lm" ./configure --enable-shared --prefix="$PREFIX" make sudo make install
(2) By Richard Hipp (drh) on 2020-06-23 10:03:32 in reply to 1 [link] [source]
Wouldn't it be easier to just do the following (which is known to work):
./configure --enable-debug --enable-all && make
I don't know why your build is segfaulting. Perhaps you could run it in "gdb" and report a stack on this mailing list.
(3) By anonymous on 2020-06-24 09:37:08 in reply to 2 [link] [source]
And here is the result when I use the mentioned option (Note that is the last part!) checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking for fdatasync... yes checking for usleep... yes checking for fullfsync... no checking for localtime_r... yes checking for gmtime_r... yes checking whether strerror_r is declared... yes checking for strerror_r... yes checking whether strerror_r returns char *... no checking editline/readline.h usability... no checking editline/readline.h presence... no checking for editline/readline.h... no checking readline/readline.h usability... yes checking readline/readline.h presence... yes checking for readline/readline.h... yes checking for library containing tgetent... -ltermcap checking for library containing readline... -lreadline checking for library containing pthread_create... -lpthread checking for library containing pthread_mutexattr_init... none required checking for library containing dlopen... -ldl checking for whether to support dynamic extensions... yes checking for library containing log... -lm checking for posix_fallocate... yes checking zlib.h usability... yes checking zlib.h presence... yes checking for zlib.h... yes checking for library containing deflate... -lz checking for library containing system... none required checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating sqlite3.pc config.status: executing depfiles commands config.status: executing libtool commands configure: WARNING: unrecognized options: --enable-all make: Nothing to be done for 'all'. So I removed the directory, unpacked and I compiled source. I am able to reproduce the error I had on the Linux Mint system when I execute .selecttrace. Here is the message: fish: “./sqlite3” terminated by signal SIGSEGV (Address boundary error)
(4) By anonymous on 2020-06-24 10:06:02 in reply to 2 [link] [source]
Here is the GDB info fish: “./sqlite3” terminated by signal SIGSEGV (Address boundary error) Program received signal SIGSEGV, Segmentation fault. 0x000055555556888c in integerValue (zArg=0x0) at shell.c:762 762 if( zArg[0]=='-' ){ -- more source lines 755 { "GB", 1000000000 }, 756 { "K", 1000 }, 757 { "M", 1000000 }, 758 { "G", 1000000000 }, 759 }; 760 int i; 761 int isNeg = 0; 762 if( zArg[0]=='-' ){ 763 isNeg = 1; 764 zArg++; p v = 0 aMult = {{zSuffix = 0x55555570e695 "KiB", iMult = 1024}, {zSuffix = 0x55555570e699 "MiB", iMult = 1048576}, {zSuffix = 0x55555570e69d "GiB", iMult = 1073741824}, {zSuffix = 0x55555570e6a1 "KB", iMult = 1000}, {zSuffix = 0x55555570e6a4 "MB", iMult = 1000000}, {zSuffix = 0x55555570e6a7 "GB", iMult = 1000000000}, { zSuffix = 0x55555570e6aa "K", iMult = 1000}, {zSuffix = 0x55555570e6ac "M", iMult = 1000000}, {zSuffix = 0x55555570e6ae "G", iMult = 1000000000}} i = 21845 isNeg = 0 l Is tthis a problem? → zArg = 0x0 bt #0 integerValue (zArg=0x0) at shell.c:762 #1 0x000055555558f7c9 in do_meta_command (zLine=0x5555557d9440 ".selecttrace", p=0x7fffffffc8f0) at shell.c:17488 #2 0x0000555555593094 in process_input (p=0x7fffffffc8f0) at shell.c:18718 #3 0x0000555555594ef6 in main (argc=1, argv=0x7fffffffdef8) at shell.c:19521
(5) By Richard Hipp (drh) on 2020-06-24 12:00:46 in reply to 4 [link] [source]
Please try again using the latest Prerelease Snapshot and report back if you continue to have problems.
(6) By anonymous on 2020-06-24 12:37:53 in reply to 5 [link] [source]
Problem solved on Ubuntu! Thx. I will check Mint later today…
(7) By anonymous on 2020-06-24 19:27:35 in reply to 5 [link] [source]
Problem is also solved for the Mint platform! Thx Is there documentation how to interpret the .selecttrace log
(8) By Richard Hipp (drh) on 2020-06-24 20:19:16 in reply to 7 [link] [source]
Is there documentation how to interpret the .selecttrace log
No. The ".selecttrace" command is designed for use by the developers when debugging the code generator. The flags that ".selecttrace" accepts and the output from ".selecttrace" changes from one release to the next. We can, and often do, change the behavior of ".selecttrace" depending on what problem we are working on and the data structure visualization needs associated with that problem.
The general idea remains the same, however. The sqlite3Select() routine is invoked with a pointer to a Select object. A Select object is the head of a tree that describes a single SELECT statement. This Select object will be processed and transformed in order to generate byte-code to implement the SELECT statement. The ".selecttrace" command outputs snapshots of the Select object and all of its substructure as the object is processed.
Usually we invoke ".selecttrace 0xffff". That turns on all of the tracing capabilities. When we run a query. The first graph shows the raw parse tree straight out of the parser. The first transformation is to walk the graph and resolve all of the identifiers and expand "*" operators in the result set. After this name resolution, the graph is redrawn. Then various optimizations are applied, which typically transform the graph further.
Note that when there are subqueries, the sqlite3Select() routine is invoked recursively. Each entry and exit from sqlite3Select() is announced.
It is usually necessary to be looking at the source code in order to understand the details of what the .selecttrace output means.
(9) By anonymous on 2020-06-25 12:20:27 in reply to 8 [link] [source]
Its the bytre code I want to read. Try this example: -- character encoding PRAGMA encoding = 'UTF-16le'; -- Journalling mode PRAGMA journal_mode=WAL; -- Automatic ANALYZE PRAGMA optimize; CREATE TABLE IF NOT EXISTS A1 ( A1_INDEX VARCHAR(20), A1_CAT VARCHAR(1) DEFAULT 'W', A1_STOCK_MIN INTEGER, A1_STOCK_LEVEL INTEGER, A1_PRODUCT TEXT, A1_STATUS NUMBER CHECK (A1_STATUS IN (1, 2, 4, 8, 16, 32, 64, 128)) DEFAULT 1, A1_REF VARCHAR(20) CHECK (A1_REF != A1_INDEX), A1_DTS_CREATED TEXT NOT NULL DEFAULT (DATETIME('NOW', 'UTC')), A1_DTS_UPDATED TEXT NOT NULL DEFAULT (DATETIME('NOW', 'UTC')), CONSTRAINT LOCATION_PK PRIMARY KEY ( A1_INDEX, A1_CAT ) -- UNIQUE ( -- A1_INDEX, -- A1_CAT, -- ) ON CONFLICT ROLLBACK ); INSERT INTO A1 (A1_INDEX, A1_STOCK_MIN, A1_STOCK_LEVEL, A1_PRODUCT, A1_REF) VALUES (12, cast(abs((0.0661 * random()) % 997 +1) as integer), ABS(RANDOM() % 14731) + 1, 'Drei im Weggla', NULL), ( 7, cast(abs((0.0661 * random()) % 997 +1) as integer), ABS(RANDOM() % 14731) + 1, 'Blaue Zipfel mit Brezel', NULL), (17, cast(abs((0.0661 * random()) % 997 +1) as integer), ABS(RANDOM() % 14731) + 1, 'Nürnberger Rostbratwurst', NULL), (14, cast(abs((0.0661 * random()) % 997 +1) as integer), ABS(RANDOM() % 14731) + 1, 'Brätwurst', 17), (19, cast(abs((0.0661 * random()) % 997 +1) as integer), ABS(RANDOM() % 14731) + 1, 'Brühwürste', NULL); CREATE TRIGGER IF NOT EXISTS A1_STOCK_UPDATE BEFORE UPDATE ON A1 WHEN (A1_STATUS = 2) AND (A1_REF ISNULL) BEGIN SELECT CASE 1 WHEN (NEW.A1_STATUS == 2) THEN CASE 1 WHEN (NOT (OLD.A1_STATUS IN (1, 8, 32, 64))) OR (((OLD.A1_REF NOT NULL)) AND (NOT (OLD.A1_STATUS == 4))) THEN RAISE (ABORT, 'Error: someone goofed') END END END; END; ~ ~ It will not work and result in all sorts of erros
(10) By TripeHound on 2020-06-25 13:28:55 in reply to 9 [link] [source]
I've just pasted that into an sqlite3 prompt and tried:
update a1 set a1_stock_min=222 where a1_index=12 ;
which gives:
Error: no such column: A1_STATUS
leading me to suspect:
WHEN (A1_STATUS = 2) AND (A1_REF ISNULL)
should have OLD.
or NEW.
added to A1_STATUS
and A1_REF
. Adding either allows the update to work (though I've no idea whether the trigger is doing what it's meant to do).
I don't know what "all sorts of errors" you're seeing, but a good starting point if there are lot (whether it's SQL or compiler errors) is to ignore everything except the first one. Fix that then try again.
(11) By anonymous on 2020-06-25 18:12:52 in reply to 10 [link] [source]
Which is correct. I should have issued a NEW in front of the variables. However: The missing NEW isn't detected when I build the database. I think that this is an error in the build function. But it gets a little stranger when you execute this trigger with the .selecttrace option. Notice that SQLite has detected that A1_STATUS is available at the start! I get the impression that the 'sudden death' of the optimizer function that halts the execution. Here is the result: SQLite version 3.33.0 2020-06-24 11:45:35 Enter ".help" for usage hints. sqlite> .selecttrace 0xffff sqlite> update a1 set ...> a1_status = 2 ...> where a1_index == 17; 1/0/563925A66748: begin processing: '-- SELECT (1/563925A66748) selFlags=0x0 nSelectRow=0 |-- result-set | '-- op=177 |-- FROM | '-- {-1:*} main.sqlite_master '-- ORDERBY '-- ID "rowid" 1/0/563925A66748: after name resolution: '-- SELECT (1/563925A66748) selFlags=0xc4 nSelectRow=0 |-- result-set | |-- AS type | | '-- {0:0} pTab=563925AC8BB8 fg.af=800000.n | |-- AS name | | '-- {0:1} pTab=563925AC8BB8 fg.af=800000.n | |-- AS tbl_name | | '-- {0:2} pTab=563925AC8BB8 fg.af=800000.n | |-- AS rootpage | | '-- {0:3} pTab=563925AC8BB8 fg.af=800000.n | '-- AS sql | '-- {0:4} pTab=563925AC8BB8 fg.af=800000.n |-- FROM | '-- {0:*} main.sqlite_master tab='sqlite_master' nCol=5 ptr=563925AC8BB8 used=1f '-- ORDERBY '-- {0:-1} pTab=563925AC8BB8 fg.af=800000.D 1/0/563925A66748: generating column names 1/0/563925A66748: Constant propagation not helpful 1/0/563925A66748: After all FROM-clause analysis: '-- SELECT (1/563925A66748) selFlags=0xc4 nSelectRow=0 |-- result-set | |-- AS type | | '-- {0:0} pTab=563925AC8BB8 fg.af=800000.n | |-- AS name | | '-- {0:1} pTab=563925AC8BB8 fg.af=800000.n | |-- AS tbl_name | | '-- {0:2} pTab=563925AC8BB8 fg.af=800000.n | |-- AS rootpage | | '-- {0:3} pTab=563925AC8BB8 fg.af=800000.n | '-- AS sql | '-- {0:4} pTab=563925AC8BB8 fg.af=800000.n |-- FROM | '-- {0:*} main.sqlite_master tab='sqlite_master' nCol=5 ptr=563925AC8BB8 used=1f '-- ORDERBY '-- {0:-1} pTab=563925AC8BB8 fg.af=800000.D 1/0/563925A66748: WhereBegin 1/0/563925A66748: end processing '-- SELECT (1/563925A66748) selFlags=0xc4 nSelectRow=200 |-- result-set | |-- AS type | | '-- {0:0} pTab=563925AC8BB8 fg.af=800000.n | |-- AS name | | '-- {0:1} pTab=563925AC8BB8 fg.af=800000.n | |-- AS tbl_name | | '-- {0:2} pTab=563925AC8BB8 fg.af=800000.n | |-- AS rootpage | | '-- {0:3} pTab=563925AC8BB8 fg.af=800000.n | '-- AS sql | '-- {0:4} pTab=563925AC8BB8 fg.af=800000.n |-- FROM | '-- {0:*} main.sqlite_master tab='sqlite_master' nCol=5 ptr=563925AC8BB8 used=1f '-- ORDERBY '-- {0:-1} pTab=563925AC8BB8 fg.af=800000.D Error: no such column: A1_STATUS SQLite suddenly kills the transaction while it tries to optimize the code. I will add the NEW tomorrow and rerun the test. I am expecting that it will fail executing the condition.
(12) By anonymous on 2020-06-26 06:14:52 in reply to 11 [link] [source]
Here is the test with the corrected code: -- character encoding PRAGMA encoding = 'UTF-16le'; -- Journalling mode PRAGMA journal_mode=WAL; -- Automatic ANALYZE PRAGMA optimize; CREATE TABLE IF NOT EXISTS A1 ( A1_INDEX VARCHAR(20), A1_CAT VARCHAR(1) DEFAULT 'W', A1_STOCK_MIN INTEGER, A1_STOCK_LEVEL INTEGER, A1_PRODUCT TEXT, A1_STATUS NUMBER CHECK (A1_STATUS IN (1, 2, 4, 8, 16, 32, 64, 128)) DEFAULT 1, A1_REF VARCHAR(20) CHECK (A1_REF != A1_INDEX), A1_DTS_CREATED TEXT NOT NULL DEFAULT (DATETIME('NOW', 'UTC')), A1_DTS_UPDATED TEXT NOT NULL DEFAULT (DATETIME('NOW', 'UTC')), CONSTRAINT LOCATION_PK PRIMARY KEY ( A1_INDEX, A1_CAT ) -- UNIQUE ( -- A1_INDEX, -- A1_CAT, -- ) ON CONFLICT ROLLBACK ); INSERT INTO A1 (A1_INDEX, A1_STOCK_MIN, A1_STOCK_LEVEL, A1_PRODUCT, A1_REF) VALUES (12, cast(abs((0.0661 * random()) % 997 +1) as integer), ABS(RANDOM() % 14731) + 1, 'Drei im Weggla', NULL), ( 7, cast(abs((0.0661 * random()) % 997 +1) as integer), ABS(RANDOM() % 14731) + 1, 'Blaue Zipfel mit Brezel', NULL), (17, cast(abs((0.0661 * random()) % 997 +1) as integer), ABS(RANDOM() % 14731) + 1, 'Nürnberger Rostbratwurst', NULL), (14, cast(abs((0.0661 * random()) % 997 +1) as integer), ABS(RANDOM() % 14731) + 1, 'Brätwurst', 17), (19, cast(abs((0.0661 * random()) % 997 +1) as integer), ABS(RANDOM() % 14731) + 1, 'Brühwürste', NULL); CREATE TRIGGER IF NOT EXISTS A1_STOCK_UPDATE BEFORE UPDATE ON A1 WHEN (NEW.A1_STATUS = 2) AND (NEW.A1_REF ISNULL) BEGIN SELECT CASE 1 WHEN (NEW.A1_STATUS == 2) THEN CASE 1 WHEN (NOT (OLD.A1_STATUS IN (1, 8, 32, 64))) OR (((OLD.A1_REF NOT NULL)) AND (NOT (OLD.A1_STATUS == 4))) THEN RAISE (ABORT, 'Error: someone goofed') END END END; END; Here is the test: .selecttrace 0xfffff UPDATE A1 SET A1_STATUS = 2 WHERE A1_INDEX == 14; Here is the .selecttrace '-- SELECT (1/55A1FF75DF48) selFlags=0x0 nSelectRow=0 '-- result-set '-- AS END '-- CASE |-- 1 '-- LIST |-- EQ fg.af=40000000.n DDL | |-- DOT fg.af=40000000.n DDL | | |-- ID "NEW" | | '-- ID "A1_STATUS" | '-- 2 '-- CASE |-- 1 '-- LIST |-- OR fg.af=40000000.n DDL | |-- NOT fg.af=40000000.n DDL | | '-- IN flags=0x40000000 | | |-- DOT fg.af=40000000.n DDL | | | |-- ID "OLD" | | | '-- ID "A1_STATUS" | | '-- LIST | | |-- 1 | | |-- 8 | | |-- 32 | | '-- 64 | '-- AND fg.af=40000000.n DDL | |-- NOTNULL fg.af=40000000.n DDL | | '-- DOT fg.af=40000000.n DDL | | |-- ID "OLD" | | '-- ID "A1_REF" | '-- NOT fg.af=40000000.n DDL | '-- EQ fg.af=40000000.n DDL | |-- DOT fg.af=40000000.n DDL | | |-- ID "OLD" | | '-- ID "A1_STATUS" | '-- 4 '-- RAISE abort('Error: someone goofed') 1/0/55A1FF75DF48: after name resolution: '-- SELECT (1/55A1FF75DF48) selFlags=0x4000c4 nSelectRow=0 '-- result-set '-- AS END '-- CASE |-- 1 '-- LIST |-- EQ fg.af=40000000.n DDL | |-- NEW(5) | '-- 2 '-- CASE |-- 1 '-- LIST |-- OR fg.af=40000000.n DDL | |-- NOT fg.af=40000000.n DDL | | '-- IN flags=0x40000000 | | |-- OLD(5) | | '-- LIST | | |-- 1 | | |-- 8 | | |-- 32 | | '-- 64 | '-- AND fg.af=40000000.n DDL | |-- NOTNULL fg.af=40000000.n DDL | | '-- OLD(6) | '-- NOT fg.af=40000000.n DDL | '-- EQ fg.af=40000000.n DDL | |-- OLD(5) | '-- 4 '-- RAISE abort('Error: someone goofed') 1/0/55A1FF75DF48: Constant propagation not helpful 1/0/55A1FF75DF48: After all FROM-clause analysis: '-- SELECT (1/55A1FF75DF48) selFlags=0x4000c4 nSelectRow=0 '-- result-set '-- AS END '-- CASE |-- 1 '-- LIST |-- EQ fg.af=40000000.n DDL | |-- NEW(5) | '-- 2 '-- CASE |-- 1 '-- LIST |-- OR fg.af=40000000.n DDL | |-- NOT fg.af=40000000.n DDL | | '-- IN flags=0x40000000 | | |-- OLD(5) | | '-- LIST | | |-- 1 | | |-- 8 | | |-- 32 | | '-- 64 | '-- AND fg.af=40000000.n DDL | |-- NOTNULL fg.af=40000000.n DDL | | '-- OLD(6) | '-- NOT fg.af=40000000.n DDL | '-- EQ fg.af=40000000.n DDL | |-- OLD(5) | '-- 4 '-- RAISE abort('Error: someone goofed') 1/0/55A1FF75DF48: WhereBegin 1/0/55A1FF75DF48: end processing '-- SELECT (1/55A1FF75DF48) selFlags=0x4000c4 nSelectRow=0 '-- result-set '-- AS END '-- CASE |-- 1 '-- LIST |-- EQ fg.af=40000000.n DDL | |-- NEW(5) | '-- 2 '-- CASE |-- 1 '-- LIST |-- OR fg.af=40000000.n DDL | |-- NOT fg.af=40000000.n DDL | | '-- IN flags=0x42000000 | | |-- OLD(5) | | '-- LIST | | |-- 1 | | |-- 8 | | |-- 32 | | '-- 64 | '-- AND fg.af=40000000.n DDL | |-- NOTNULL fg.af=40000000.n DDL | | '-- OLD(6) | '-- NOT fg.af=40000000.n DDL | '-- EQ fg.af=40000000.n DDL | |-- OLD(5) | '-- 4 '-- RAISE abort('Error: someone goofed') Based on the .selecttrace I am tempted to conclude that the updated isn't executed. If I check the column the update was executed. Observations why is are there 4 attempts after the row was selected?
(13) By anonymous on 2020-06-26 09:05:44 in reply to 12 [source]
And then I changed the A1_STATUS to 1 which should ignore the trigger after testing the condition. Here is the test: .selecttrace 0xfffff UPDATE A1 SET A1_STATUS = 1 WHERE A1_INDEX == 14; Examining the .selecttrace log I discovered that the SQLite optimize-function attempts to execute((?) or scan(?) the trigger. So I made an error in the trigger to proof this: CREATE TRIGGER IF NOT EXISTS A1_STOCK_UPDATE BEFORE UPDATE ON A1 WHEN (NEW.A1_STATUS = 2) AND (NEW.A1_REF ISNULL) BEGIN SELECT CASE 1 WHEN (NEW.A2_STATUS == 2) THEN CASE 1 WHEN (NOT (OLD.A1_STATUS IN (1, 8, 32, 64))) OR (((OLD.A1_REF NOT NULL)) AND (NOT (OLD.A1_STATUS == 4))) THEN RAISE (ABORT, 'Error: someone goofed') END END END; END; The error (only the final part of the .selecttrace is shown) proofs that the optimize function scans the triggers and halts the update even if the trigger is not part of the equation. Here is the final part of the .selecttrace log | | '-- 64 | '-- AND fg.af=40000000.n DDL | |-- NOTNULL fg.af=40000000.n DDL | | '-- DOT fg.af=40000000.n DDL | | |-- ID "OLD" | | '-- ID "A1_REF" | '-- NOT fg.af=40000000.n DDL | '-- EQ fg.af=40000000.n DDL | |-- DOT fg.af=40000000.n DDL | | |-- ID "OLD" | | '-- ID "A1_STATUS" | '-- 4 '-- RAISE abort('Error: someone goofed') Error: near line 3: no such column: NEW.A2_STATUS