Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
431,43 KB
Nội dung
FOR EACH ROW
BEGIN
MESSAGE STRING ( 'Trigger triud_t1 fired.' ) TO CONSOLE;
END;
INSERT t1 VALUES ( 1, 'first row' );
INSERT t1 VALUES ( 2, 'second row' );
UPDATE t1 SET non_key_1 = 'xxx';
DELETE t1;
Here’s what the output looks like; because this trigger was defined as FOR
EACH ROW, it was fired once by each INSERT, twice by the single UPDATE
statement, and twice by the DELETE for a total of six times:
Trigger triud_t1 fired.
Trigger triud_t1 fired.
Trigger triud_t1 fired.
Trigger triud_t1 fired.
Trigger triud_t1 fired.
Trigger triud_t1 fired.
Here’s an example of the same trigger, modified to execute different code
depending on which kind of SQL operation fired the trigger:
CREATE TRIGGER triud_t1
BEFORE INSERT, DELETE, UPDATE
ON t1
FOR EACH ROW
BEGIN
CASE
WHEN INSERTING THEN MESSAGE 'Inserting t1.' TO CONSOLE;
WHEN UPDATING THEN MESSAGE 'Updating t1.' TO CONSOLE;
WHEN DELETING THEN MESSAGE 'Deleting t1.' TO CONSOLE;
END CASE;
END;
INSERT t1 VALUES ( 1, 'first row' );
INSERT t1 VALUES ( 2, 'second row' );
UPDATE t1 SET non_key_1 = 'xxx';
DELETE t1;
Here’s the output; for more information about the special trigger predicates
INSERTING, DELETING and UPDATING, see Section 3.12.7, “Trigger
Predicates.”
Inserting t1.
Inserting t1.
Updating t1.
Updating t1.
Deleting t1.
Deleting t1.
Tip: Use IF and CASE statements, not IF and CASE expressions, when refer
-
ring to the special trigger predicates INSERTING, DELETING, and UPDATING in
insert and delete triggers. That’s because the REFERENCING OLD AS structure is
undefined when an INSERT fires the trigger, and the NEW AS row structure is
undefined when a DELETE fires the trigger. The THEN and ELSE expressions in IF
and CASE expressions are always parsed, even if they are not evaluated, and an
undefined row structure will cause an error. The same is not true for IF and CASE
statements; not only are the THEN and ELSE branches not evaluated if they are
not chosen, they are not even parsed. And that’s why IF and CASE statements
work in a situation like this, whereas IF and CASE expressions will fail.
286 Chapter 8: Packaging
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
An UPDATE that specifies new column values that are the same as old column
values will still fire a before row UPDATE trigger; the same is true of an
UPDATE that refers to a column named in the UPDATE OF clause but doesn’t
specify a different value. Also, the row structures contain all the column values
from the old and new rows, even columns excluded from an UPDATE OF list,
and all those other columns can be named in the WHEN clause. Here is an
example of a before row trigger with both an UPDATE OF clause and a WHEN
clause, plus code that changes the final values for all the non-key columns:
CREATE TABLE t1 (
key_1 INTEGER NOT NULL PRIMARY KEY,
non_key_1 VARCHAR ( 100 ) NOT NULL,
non_key_2 VARCHAR ( 100 ) NOT NULL );
CREATE TRIGGER triud_t1
BEFORE UPDATE OF non_key_1
ON t1
REFERENCING OLD AS old_t1
NEW AS new_t1
FOR EACH ROW
WHEN ( old_t1.non_key_2 = 'xxx' )
BEGIN
MESSAGE 'Updating t1 ' TO CONSOLE;
MESSAGE STRING ( ' Old row: ',
old_t1.key_1, ', ',
old_t1.non_key_1, ', ',
old_t1.non_key_2 ) TO CONSOLE;
MESSAGE STRING ( ' New row: ',
new_t1.key_1, ', ',
new_t1.non_key_1, ', ',
new_t1.non_key_2 ) TO CONSOLE;
SET new_t1.non_key_1 = 'ccc';
SET new_t1.non_key_2 = 'ddd';
MESSAGE STRING ( ' Final row: ',
new_t1.key_1, ', ',
new_t1.non_key_1, ', ',
new_t1.non_key_2 ) TO CONSOLE;
END;
INSERT t1 VALUES ( 1, 'ppp', 'aaa' );
INSERT t1 VALUES ( 2, 'qqq', 'bbb' );
UPDATE t1 SET non_key_2 = 'xxx' WHERE key_1 = 1;
UPDATE t1 SET non_key_1 = 'zzz' WHERE key_1 = 2;
UPDATE t1 SET non_key_1 = 'yyy';
SELECT * FROM t1 ORDER BY key_1;
The first UPDATE above doesn’t fire the trigger because the SET clause speci
-
fies a column that isn’t named in the trigger’s UPDATE OF clause. The second
UPDATE doesn’t fire the trigger because the old value of t1.non_key_2 is 'bbb'
and that doesn’t match the trigger’s WHEN clause. The third update changes
both rows in t1, but only the update to the first row fires the trigger because
that’s the only update that matches both the UPDATE OF and WHEN clauses.
The code inside the trigger then changes both non-key column values and dis
-
plays all three versions of the row: old, new, and final. Here’s what that display
looks like:
Updating t1
Old row: 1, ppp, xxx
Chapter 8: Packaging
287
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
New row: 1, yyy, xxx
Final row: 1, ccc, ddd
Here’s what the final SELECT shows after all the updates are complete:
key_1 non_key_1 non_key_2
===== ========= =========
1 'ccc' 'ddd'
2 'yyy' 'bbb'
Tip: The before row form of CREATE TRIGGER is very popular because it is the
easiest to code. For example, it is possible to modify the new row in a before row
UPDATE trigger without worrying about endless recursion. Updates made in the
other two kinds of trigger must be made directly to the associated table rather
than a row structure; that nested update may recursively fire the same trigger,
requiring extra code to make sure the recursion doesn’t run away.
The syntax for the second form of trigger differs only by one word: The key
-
word AFTER specifies that this trigger is fired after the row operation is
complete:
<create_after_row_trigger> ::= CREATE TRIGGER <trigger_name>
AFTER
<fired_by>
[ ORDER <order_number> ]
ON [ <owner_name> "." ] <table_name>
[ <referencing_as_structures> ]
FOR EACH ROW
[ WHEN "(" <boolean_expression> ")" ]
<begin_block>
After row triggers work almost the same way as before row triggers, with three
differences:
n
An after row UPDATE trigger is not fired for a row where no column val-
ues actually changed in value.
n
An after row UPDATE OF trigger is not fired for a row where none of the
columns named in the UPDATE OF clause actually changed in value.
n
It is not possible to modify the values in the REFERENCING NEW AS
structure because it’s too late, the row operation has already been
performed.
The syntax for the third form of trigger uses the keywords AFTER and FOR
EACH STATEMENT to define a trigger that is fired once after the triggering
INSERT, UPDATE, or DELETE statement is finished operating on all the rows
it affects:
<create_after_statement_trigger> ::= CREATE TRIGGER <trigger_name>
AFTER
<fired_by>
[ ORDER <order_number> ]
ON [ <owner_name> "." ] <table_name>
[ <referencing_as_tables> ]
[ FOR EACH STATEMENT ]
<begin_block>
<referencing_as_tables> ::= REFERENCING { <as_table> } <as_table>
<as_table> ::= OLD AS <as_table_name>
| NEW AS <as_table_name>
<as_table_name> ::= <identifier> naming a read-only temporary table
288 Chapter 8: Packaging
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Here’s a list of characteristics that make an after statement trigger different from
an after row trigger:
n
The REFERENCING OLD AS and NEW AS clauses define multi-row
temporary tables as opposed to single-row structures.
n
The REFERENCING OLD AS temporary table contains the rows affected
by the statement that caused the trigger to fire, as they existed in the data
-
base before the triggering statement executed.
n
The REFERENCING NEW AS temporary table contains the rows affected
by the statement that caused the trigger to fire, as they exist in the database
after the triggering statement finished but before the trigger itself began
executing.
n
The REFERENCING NEW AS temporary table itself is read-only,
although it can be used in a join in an UPDATE statement inside the trigger.
n
The WHEN clause is not allowed in an after statement trigger.
n
The REFERENCING OLD AS and NEW AS temporary tables can be
empty if the triggering statement doesn’t actually affect any rows in the
table. An after statement trigger is always fired if the other criteria are met;
e.g., an UPDATE OF trigger is fired if the UPDATE statement contains a
SET clause that specifies at least one of the columns named in the trigger’s
UPDATE OF clause, even if the UPDATE statement’s WHERE clause
didn’t match any rows.
n
The REFERENCING OLD AS and NEW AS temporary tables in an after
statement UPDATE or UPDATE OF trigger won’t contain any rows where
the column values didn’t actually change. This means the temporary tables
can be empty or can contain fewer rows than the UPDATE statement’s
WHERE clause matched.
The rules for when an after statement trigger is fired, and if so, how many rows
appear in the REFERENCING OLD AS and NEW AS temporary tables, are
rather complex. Following are two tables that summarize the rules, and include
the before row and after row triggers as well. Each table entry answers two
questions: “Is this trigger fired, yes or no?” and “For an after statement trigger,
how many rows appear in the REFERENCING temporary tables?” For simplic
-
ity, the tables assume an UPDATE statement that matches either one or zero
rows.
The first table is for an ordinary UPDATE trigger, one that doesn’t use the
special UPDATE OF clause. Whether or not this class of trigger is fired depends
on whether or not the WHERE clause matches any rows, and whether or not the
SET clause specifies any column values that are different.
UPDATE Trigger Fired?
WHERE clause matches row: yes yes no
SET clause specifies value: different same n/a
========== =========== ===========
BEFORE UPDATE ROW yes yes no
AFTER UPDATE ROW yes no no
AFTER UPDATE STATEMENT yes, 1 row yes, 0 rows yes, 0 rows
The second table is for a trigger with an UPDATE OF clause. Whether or not
this class of trigger is fired depends on whether or not the WHERE clause
matches any rows, whether or not the SET clause names any columns also
Chapter 8: Packaging
289
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
named in the UPDATE OF clause, and whether or not the SET clause specifies
any column values that are different.
UPDATE OF Trigger Fired?
WHERE clause matches row: yes yes yes no no
SET clause matches UPDATE OF: yes yes no yes no
SET clause specifies value: different same - - -
========== =========== ==== =========== ====
BEFORE UPDATE OF ROW yes yes no no no
AFTER UPDATE OF ROW yes no no no no
AFTER UPDATE OF STATEMENT yes, 1 row yes, 0 rows no yes, 0 rows no
Following is an example of an after statement trigger that is fired by an
UPDATE statement that matches two rows. The trigger BEGIN block includes
cursor FOR loops and MESSAGE statements to display the entire contents of
the REFERENCING OLD AS and NEW AS temporary tables.
This trigger also contains an UPDATE statement that overrides the changes
made by the triggering UPDATE statement by directly updating the table again.
This will fire the trigger recursively, so the trigger takes the following two steps
to prevent runaway recursion. First, the UPDATE statement inside the trigger
includes a WHERE clause that won’t match any rows that have already been
changed by a previous trigger execution. Second, the first statement in the trig-
ger BEGIN block is an IF that checks how many rows are in the
REFERENCING OLD AS temporary table. If that temporary table is empty
(which will happen if it is fired by an UPDATE that doesn’t match any rows),
the LEAVE statement terminates the trigger before it has a chance to fire itself
again.
CREATE TABLE t1 (
key_1 INTEGER NOT NULL PRIMARY KEY,
non_key_1 VARCHAR ( 100 ) NOT NULL,
non_key_2 VARCHAR ( 100 ) NOT NULL );
CREATE TRIGGER tru_t1
AFTER UPDATE OF non_key_1
ON t1
REFERENCING OLD AS old_t1
NEW AS new_t1
FOR EACH STATEMENT
this_trigger:
BEGIN
MESSAGE 'Updating t1 ' TO CONSOLE;
IF NOT EXISTS ( SELECT * FROM old_t1 ) THEN
MESSAGE ' no rows updated.' TO CONSOLE;
LEAVE this_trigger;
END IF;
FOR f1 AS c1 NO SCROLL CURSOR FOR
SELECT old_t1.key_1 AS @key_1,
old_t1.non_key_1 AS @non_key_1,
old_t1.non_key_2 AS @non_key_2
FROM old_t1
ORDER BY old_t1.key_1
DO
MESSAGE STRING ( ' Old row: ',
@key_1, ', ',
@non_key_1, ', ',
@non_key_2 ) TO CONSOLE;
290 Chapter 8: Packaging
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
END FOR;
FOR f2 AS c2 NO SCROLL CURSOR FOR
SELECT new_t1.key_1 AS @key_1,
new_t1.non_key_1 AS @non_key_1,
new_t1.non_key_2 AS @non_key_2
FROM new_t1
ORDER BY new_t1.key_1
DO
MESSAGE STRING ( ' New row: ',
@key_1, ', ',
@non_key_1, ', ',
@non_key_2 ) TO CONSOLE;
END FOR;
UPDATE t1
INNER JOIN new_t1
ON new_t1.key_1 = t1.key_1
SET t1.non_key_1 = 'ccc',
t1.non_key_2 = 'ddd'
WHERE t1.non_key_1 <> 'ccc'
OR t1.non_key_2 <> 'ddd';
FOR f4 AS c4 NO SCROLL CURSOR FOR
SELECT t1.key_1 AS @key_1,
t1.non_key_1 AS @non_key_1,
t1.non_key_2 AS @non_key_2
FROM t1
INNER JOIN new_t1
ON new_t1.key_1 = t1.key_1
ORDER BY t1.key_1
DO
MESSAGE STRING ( 'Final row: ',
@key_1, ', ',
@non_key_1, ', ',
@non_key_2 ) TO CONSOLE;
END FOR;
END;
INSERT t1 VALUES ( 1, 'ppp', 'aaa' );
INSERT t1 VALUES ( 2, 'qqq', 'bbb' );
UPDATE t1 SET non_key_1 = 'yyy';
SELECT * FROM t1 ORDER BY key_1;
Note: A runaway trigger will run for quite a while, firing itself over and over
again many times, but SQLAnywhere will eventually detect an error and set the
SQLSTATE to '42W29' for “Procedure or trigger calls have nested too deeply.”
The MESSAGE output shows that the trigger is fired three times, once by the
outer UPDATE, once by the UPDATE in the first trigger execution that changes
the rows a second time, and once for the UPDATE in the second trigger execu
-
tion that doesn’t match any rows:
Updating t1
Old row: 1, ppp, aaa
Old row: 2, qqq, bbb
New row: 1, yyy, aaa
New row: 2, yyy, bbb
Chapter 8: Packaging
291
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Updating t1
Old row: 1, yyy, aaa
Old row: 2, yyy, bbb
New row: 1, ccc, ddd
New row: 2, ccc, ddd
Updating t1
no rows updated.
Final row: 1, ccc, ddd
Final row: 2, ccc, ddd
Final row: 1, ccc, ddd
Final row: 2, ccc, ddd
The output from the SELECT shows the final contents of the table:
key_1 non_key_1 non_key_2
===== ========= =========
1 'ccc' 'ddd'
2 'ccc' 'ddd'
Triggers can be used for complex integrity checks and for calculations in a
denormalized database design. For example, here is a trigger that updates a run
-
ning total in a parent table every time a row in a child table is inserted, updated,
or deleted. For every INSERT, the inserted value in child.non_key_3 is added to
the corresponding parent.non_key_3; for every DELETE, the deleted value is
subtracted; and every UPDATE subtracts the old value and adds the new value.
CREATE TRIGGER tr_child
BEFORE INSERT, DELETE, UPDATE
ORDER 1 ON child
REFERENCING OLD AS old_child
NEW AS new_child
FOR EACH ROW
BEGIN
CASE
WHEN INSERTING THEN
UPDATE parent
SET parent.non_key_3
= parent.non_key_3
+ new_child.non_key_3
WHERE parent.key_1 = new_child.key_1;
WHEN UPDATING THEN
UPDATE parent
SET parent.non_key_3
= parent.non_key_3
- old_child.non_key_3
+ new_child.non_key_3
WHERE parent.key_1 = old_child.key_1;
WHEN DELETING THEN
UPDATE parent
SET parent.non_key_3
= parent.non_key_3
- old_child.non_key_3
WHERE parent.key_1 = old_child.key_1;
END CASE;
END;
292 Chapter 8: Packaging
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Tip: Avoid writing triggers. They’re hard to code, hard to understand, hard to
test, hard to debug, and prone to errors and performance problems. SQL Any
-
where has many features you can use to avoid writing triggers: primary and
foreign key constraints, UNIQUE constraints, CHECK constraints, computed col
-
umns, and DEFAULT values like TIMESTAMP, LAST USER, AUTOINCREMENT and
GLOBAL AUTOINCREMENT, all of which are described in Chapter 1, “Creating.”
8.12 CREATE EVENT
An event is a special kind of BEGIN block that is stored in the database. Each
event may be associated with a named occurrence or condition that SQL Any
-
where can detect or a schedule that SQLAnywhere can follow. An event is
somewhat like a trigger in that it can be automatically executed by SQL Any
-
where. Unlike a trigger, however, an event is not associated with any table in the
database, and it can be explicitly executed as well as fired automatically.
Events come in three basic flavors: typed events that are associated with a
named condition or event type, scheduled events that are executed according to
a clock and calendar schedule, and user-defined events that are explicitly exe-
cuted via the TRIGGER EVENT statement described in Section 8.13.
<create_event> ::= <create_typed_event>
| <create_scheduled_event>
| <create_user_defined_event>
A typed event is associated with one of 14 different conditions or event types.
Most of these event types are associated with specific occurrences that SQL
Anywhere can detect and react to as soon as they occur; e.g., "Connect" repre-
sents a user connection being successfully established. Four of these event types
— DBDiskSpace, LogDiskSpace, ServerIdle, and TempDiskSpace — require
active polling, which is done by SQLAnywhere every 30 seconds.
<create_typed_event> ::= CREATE EVENT <event_name>
TYPE <event_type>
[ <event_where_clause> ]
HANDLER <begin_block>
<event_name> ::= <identifier>
<event_type> ::= BackupEnd backup completed
| "Connect" user connected OK
| ConnectFailed user connection failed
| DatabaseStart database started
| DBDiskSpace checked every 30 seconds
| "Disconnect" user disconnected
| GlobalAutoincrement near end of range
| GrowDB database file extended
| GrowLog transaction log extended
| GrowTemp temporary file extended
| LogDiskSpace checked every 30 seconds
| "RAISERROR" RAISERROR issued
| ServerIdle checked every 30 seconds
| TempDiskSpace checked every 30 seconds
The event WHERE clause may be used to limit the conditions under which a
typed event is actually executed. Different event types have different measure
-
ments associated with them, available through calls to the built-in
EVENT_CONDITION function. The WHERE clause can be used to compare
Chapter 8: Packaging
293
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
these measurements to literal values in a simple boolean expression using
numeric comparison predicates and the AND operator:
<event_where_clause> ::= WHERE <event_predicate> { AND <event_predicate> }
<event_predicate> ::= EVENT_CONDITION "(" <event_condition_name> ")"
<event_comparison_operator>
<event_condition_value>
<event_condition_name> ::= 'DBFreePercent' for DBDiskSpace
| 'DBFreeSpace' for DBDiskSpace, in MB
| 'DBSize' for GrowDB, in MB
| 'ErrorNumber' for "RAISERROR"
| 'IdleTime' for ServerIdle, in seconds
| 'Interval' for all, in seconds
| 'LogFreePercent' for LogDiskSpace
| 'LogFreeSpace' for LogDiskSpace, in MB
| 'LogSize' for GrowLog, in MB
| 'RemainingValues' for GlobalAutoincrement
| 'TempFreePercent' for TempDiskSpace
| 'TempFreeSpace' for TempDiskSpace, in MB
| 'TempSize' for GrowTemp, in MB
<event_comparison_operator> ::= "-"
| "<"
| ">"
| "!="
| "<="
| ">="
<event_condition_value> ::= integer literal value for comparison
Note: The CREATE EVENT statement has other keywords you can read about
in the SQLAnywhere Help. The DISABLE keyword may be used to create an
event that won’t be automatically executed, no matter what, until an ALTER
EVENT statement specifies ENABLE; by default events are enabled, and the
ALTER EVENT statement isn’t discussed in this book. Also, the AT CONSOLI-
DATED and AT REMOTE clauses can be used to control where events will be
executed in a SQL Remote environment; this book doesn’t discuss SQL Remote,
just MobiLink, so these AT clauses aren’t covered either.
Only the string literal <event_condition_name> values listed above can be used
as EVENT_CONDITION parameters. They aren’t case sensitive, but they are
checked for syntax; any spelling mistake or attempt to use an expression will
cause the CREATE EVENT statement to fail.
The EVENT_CONDITION return value is numeric. Except for 'Interval',
each event condition name only applies to one event type; EVENT_CONDI
-
TION returns zero for any event condition name that is used with an event type
to which it doesn’t apply.
The EVENT_CONDITION function can only be called in the WHERE
clause as shown above; if you need the same information inside the event’s
BEGIN block you can call the EVENT_PARAMETER function.
EVENT_PARAMETER accepts all the same condition names as
EVENT_CONDITION, plus some additional predefined parameters listed here:
<event_parameter_function_call> ::= EVENT_PARAMETER
"(" <event_parameter_name_string> ")"
<event_parameter_name_string> ::= string expression containing an
<event_parameter_name>
<event_parameter_name> ::= DBFreePercent from EVENT_CONDITION
294 Chapter 8: Packaging
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
| DBFreeSpace
| DBSize
| ErrorNumber
| IdleTime
| Interval
| LogFreePercent
| LogFreeSpace
| LogSize
| RemainingValues
| TempFreePercent
| TempFreeSpace
| TempSize
| AppInfo more predefined names
| ConnectionID
| DisconnectReason
| EventName
| Executions
| NumActive
| ScheduleName
| TableName
| User
| <user_defined_event_parameter_name>
<user_defined_event_parameter_name> ::= <identifier>
The argument to EVENT_PARAMETER is a string containing the name of an
event parameter; e.g., EVENT_PARAMETER ( 'User' ) will return the user id
that invoked this event. Unlike the argument to EVENT_CONDITION,
EVENT_PARAMETER can be passed an expression as long as the result of that
expression is one of the predefined parameter names listed above, or a
user-defined parameter name.
The EVENT_PARAMETER return value is VARCHAR ( 254 ); alphanu-
meric and numeric values are all returned as strings. The default values are the
empty string '' for predefined alphanumeric parameters, '0' for predefined
numeric parameters, and NULL for user-defined parameters that haven’t been
given a value in a TRIGGER EVENT statement. For more information about
user-defined parameters, see Section 8.13, “TRIGGER EVENT.”
Here is an example of a ServerIdle typed event handler that uses a WHERE
clause to start executing as soon as the server has been idle for 60 seconds:
CREATE EVENT ev_ServerIdle
TYPE ServerIdle
WHERE EVENT_CONDITION ( 'IdleTime' ) >= 60
HANDLER BEGIN
MESSAGE STRING (
'The server has been idle for ',
EVENT_PARAMETER ( 'IdleTime' ),
' seconds.' ) TO CONSOLE;
END;
Here is the output produced by that event handler; SQLAnywhere polls for this
kind of event every 30 seconds, and the WHERE clause prevented the event
handler from executing at the first 30-second point:
The server has been idle for 60 seconds.
The server has been idle for 90 seconds.
The server has been idle for 120 seconds.
The server has been idle for 150 seconds.
The server has been idle for 180 seconds.
The server has been idle for 210 seconds.
Chapter 8: Packaging
295
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
[...]... client-side SQLCA.AutoCommit setting used by the PowerBuilder application when connecting via ODBC to the database The second column shows the server-side setting of the CHAINED option used by SQLAnywhere The third column shows the SQL statements that were actually sent across the client server interface from ODBC to SQLAnywhere The fourth column shows what internal operations were performed by SQL Anywhere, ... jConnect If you happen to be using TDS but you aren’t interested in Transact SQL compatibility, you should look up “sp_tsql_environment” in the SQLAnywhere Help and make sure the option values it sets are the ones you want However, if you use ODBC, OLE DB, or embedded SQL to connect to the database, you don’t have to worry about sp_tsql_environment, as it isn’t called Please purchase PDF Split-Merge on... The CREATE VARIABLE statement may be used to create a connection-level variable in SQLAnywhere This kind of variable is also called a “global variable” because once it is created, it can be referenced by any SQL code running on the same connection; this includes procedures, triggers, and SQL statements passed to SQLAnywhere from a client application, but not events ::=... stored in the SYSOPTION table Note: Every time a new connection is established, SQLAnywhere calls the sp_login_environment built-in procedure, which in turn calls the sp_tsql_environment procedure if the communication protocol is TDS The sp_tsql_environment procedure explicitly sets several options in order to maintain Transact SQL compatibility The TDS protocol is used for connections using Sybase Open... measurement falls below 20%, SQLAnywhere will execute this event every 30 seconds Here’s what the output looks like: ev_DBDiskSpace started at 2004-01-12 13:39:56.495 DBFreePercent: 9 DBFreeSpace : 2664 Here is a TRIGGER EVENT that provides a value for DBFreePercent but not DBFreeSpace: TRIGGER EVENT ev_DBDiskSpace ( DBFreePercent = '15' ); Here is the corresponding output; SQLAnywhere doesn’t automatically... “Handler for event 'ev_ServerIdle' caused SQLSTATE '52003'” means “column not found.” Because a separate internal connection is used for each event execution, there is no “client application” to receive an error message when one is produced by an event’s BEGIN block, so SQLAnywhere has nowhere else to send it other than the console window Even if you use ISQL and TRIGGER EVENT statements to test your... sp_tsql_environment, as it isn’t called Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark 310 Chapter 9: Protecting Note: After ISQL connects to the database, it explicitly sets some options for its own purposes ISQL options are described in the SQLAnywhere Help, and they aren’t discussed in detail in this book You can change option values at the public, user, and current levels using three... '100' forces SQLAnywhere to maintain performance statistics for small tables n STRING_RTRUNCATION = 'ON' means that an INSERT statement that attempts to truncate non-blank characters from the right end of a string value will raise an error instead of silently truncating those characters to make the value fit in a column The EXISTING keyword is optional but highly recommended; it prevents SQL Anywhere. .. isolation with SQLAnywhere is the row Isolation may be taken further when considering whether different transactions may even see the effects of changes made by other transactions; the ISOLATION_LEVEL option applies to this aspect, and is discussed later in this chapter As far as updates are concerned, however, isolation is not optional; once a transaction has changed a row in a table, SQLAnywhere does... the BEGIN TRANSACTION, COMMIT, or ROLLBACK statements; they have no effect in SQLAnywhere Also, the different formats for each statement are equivalent The full syntax is shown here because these different formats sometimes appear in documentation and utility program output, and they often lead to unnecessary confusion SQLAnywhere has two modes of transaction control, called “chained mode” and “unchained . firing itself over and over
again many times, but SQL Anywhere will eventually detect an error and set the
SQLSTATE to '42W29' for “Procedure or. associated with a named occurrence or condition that SQL Any
-
where can detect or a schedule that SQL Anywhere can follow. An event is
somewhat like a trigger