...How To Enjoy This Cartoon
- Read...
- Laugh.
- Look it up.
- Laugh again.
SQL Anywhere® Does Things The Way They Should Be Done.
Some programming tasks are notoriously difficult to get right but are regarded as "easy" by folks who haven't actually tackled them.
One is creating a good installation setup for a complex piece of software... proof of how difficult that is lies in the vast numbers of crappy setups that have been published over the years.
Another is displaying a decent progress indicator for a long-running process that runs as a "black box" with a beginning and an end but no outside access to intermediate steps... like a set-oriented UPDATE statement that affects millions of rows.
Here is an example of where such a progress indicator is needed: when Foxhound 1.2 upgrades the data from an earlier version it has to UPDATE all the connection-level sample data to fill in some new derived columns.
In this run the UPDATE took 19 minutes to process 6 million rows and all it displayed was an occasional "Cache size adjusted" message... not good:
I. 07/26 15:27:10. 2011-07-26 15:27:10.473 DATA UPGRADE: Upgrading existing rows.
I. 07/26 15:27:41. Cache size adjusted to 3228864K
I. 07/26 15:27:47. Cache size adjusted to 3268992K
I. 07/26 15:30:03. Cache size adjusted to 3621072K
I. 07/26 15:36:48. Cache size adjusted to 3993080K
I. 07/26 15:38:48. Cache size adjusted to 4118600K
I. 07/26 15:40:04. Cache size adjusted to 4149984K
I. 07/26 15:40:09. Cache size adjusted to 4157832K
I. 07/26 15:40:14. Cache size adjusted to 4159792K
I. 07/26 15:40:19. Cache size adjusted to 4160280K
I. 07/26 15:40:24. Cache size adjusted to 4160400K
I. 07/26 15:41:53. Starting checkpoint of "new_f" (foxhound1.db) at Tue Jul 26 2011 15:41
I. 07/26 15:43:02. Finished checkpoint of "new_f" (foxhound1.db) at Tue Jul 26 2011 15:43
I. 07/26 15:46:52. 2011-07-26 15:46:52.728 DATA UPGRADE: Creating foreign keys.
CREATE EVENT rroad_display_progress_messages
HANDLER BEGIN
DECLARE @calling_connection_id INTEGER;
DECLARE @commit_percent BIGINT;
DECLARE @continuing VARCHAR ( 1 );
DECLARE @previous_commit_message_displayed_at_loop_counter BIGINT;
DECLARE @previous_update_message_displayed_at_loop_counter BIGINT;
DECLARE @lock_count BIGINT;
DECLARE @lock_count_has_increased_at_least_once VARCHAR ( 1 );
DECLARE @loop_counter BIGINT;
DECLARE @previous_commit_percent BIGINT;
DECLARE @previous_lock_count BIGINT;
DECLARE @previous_update_percent BIGINT;
DECLARE @row_count BIGINT;
DECLARE @update_percent BIGINT;
SET @continuing = 'Y'; -- until proven otherwise
SET @calling_connection_id = CAST ( COALESCE ( EVENT_PARAMETER ( 'ConnectionID' ), '0' ) AS INTEGER );
IF @calling_connection_id <= 0 THEN
SET @continuing = 'N'; -- the calling connection id is out of range
END IF;
IF @continuing = 'Y' THEN
SET @row_count = CAST ( COALESCE ( EVENT_PARAMETER ( '@row_count_string' ), '0' ) AS BIGINT );
IF @row_count <= 0 THEN
SET @continuing = 'N'; -- the row count is out of range
END IF;
END IF;
SET @lock_count_has_increased_at_least_once = 'N';
SET @previous_update_message_displayed_at_loop_counter = 0;
SET @previous_commit_message_displayed_at_loop_counter = 0;
SET @previous_lock_count = 0;
SET @previous_update_percent = 0;
SET @previous_commit_percent = 0;
SET @loop_counter = 0;
WHILE @continuing = 'Y' LOOP
SET @loop_counter = @loop_counter + 1;
SET @lock_count = CONNECTION_PROPERTY ( 'LockCount', EVENT_PARAMETER ( 'ConnectionID' ) );
IF @lock_count IS NULL THEN
SET @continuing = 'N'; -- the calling connection no longer exist
END IF;
IF @continuing = 'Y' THEN
IF NOT EXISTS ( SELECT *
FROM rroad_progress_messages_requested
WHERE requested_by_connection_id = @calling_connection_id ) THEN
SET @continuing = 'N'; -- the caller no longer wants progress messages displayed
END IF;
END IF;
IF @continuing = 'Y' THEN
CASE
WHEN @lock_count > 0
AND @lock_count > @previous_lock_count THEN
SET @lock_count_has_increased_at_least_once = 'Y';
SET @update_percent = CAST (
( CAST ( @lock_count AS DECIMAL ( 11, 2 ) )
/ CAST ( @row_count AS DECIMAL ( 11, 2 ) ) ) * 100.00
AS BIGINT );
IF @update_percent > @previous_update_percent
OR ( @update_percent > 0
AND @update_percent = @previous_update_percent
AND @loop_counter >= @previous_update_message_displayed_at_loop_counter + 9
AND MOD ( @loop_counter, 10 ) = 0 ) THEN
MESSAGE STRING ( @update_percent, '% updated (', @lock_count, ' rows of ', @row_count, ')' ) TO CONSOLE;
SET @previous_update_message_displayed_at_loop_counter = @loop_counter;
END IF;
SET @previous_update_percent = @update_percent;
WHEN @lock_count > 0
AND @lock_count < @previous_lock_count
AND @lock_count_has_increased_at_least_once = 'Y' THEN
SET @commit_percent = CAST (
( ( CAST ( @row_count AS DECIMAL ( 11, 2 ) ) - CAST ( @lock_count AS DECIMAL ( 11, 2 ) ) )
/ CAST ( @row_count AS DECIMAL ( 11, 2 ) ) ) * 100.00
AS BIGINT );
IF @commit_percent > @previous_commit_percent
OR ( @commit_percent > 0
AND @commit_percent = @previous_commit_percent
AND @loop_counter >= @previous_commit_message_displayed_at_loop_counter + 9
AND MOD ( @loop_counter, 10 ) = 0 ) THEN
MESSAGE STRING ( @commit_percent, '% committed (', @row_count - @lock_count, ' rows of ', @row_count, ')' ) TO CONSOLE;
SET @previous_commit_message_displayed_at_loop_counter = @loop_counter;
END IF;
SET @previous_commit_percent = @commit_percent;
WHEN @lock_count = 0
AND @lock_count_has_increased_at_least_once = 'Y' THEN
MESSAGE STRING ( 'Done: ', @row_count, ' rows' ) TO CONSOLE;
SET @continuing = 'N';
ELSE
-- No action.
END CASE;
END IF;
IF @continuing = 'Y' THEN
SET @previous_lock_count = @lock_count;
WAITFOR DELAY '00:00:01';
END IF;
END LOOP;
END;
DECLARE @rroad_group_2_property_pivot_row_count BIGINT;
. . .
------------------------------------------------------------
-- Start displaying progress messages.
INSERT rroad_progress_messages_requested ( requested_by_connection_id ) VALUES ( @@SPID );
COMMIT;
SELECT SYSTAB.count
INTO @rroad_group_2_property_pivot_row_count
FROM SYSTAB
WHERE SYSTAB.table_name = 'rroad_group_2_property_pivot';
TRIGGER EVENT rroad_display_progress_messages (
@row_count_string = STRING ( @rroad_group_2_property_pivot_row_count ) );
------------------------------------------------------------
-- Update rroad_group_2_property_pivot with remaining calculated columns
UPDATE rroad_group_2_property_pivot
INNER JOIN rroad_sample_set
ON rroad_sample_set.sample_set_number = rroad_group_2_property_pivot.sample_set_number
LEFT OUTER JOIN ( SELECT rroad_group_2_property_pivot.sample_set_number AS sample_set_number,
. . .
COMMIT;
------------------------------------------------------------
-- Stop displaying progress messages.
DELETE rroad_progress_messages_requested
WHERE requested_by_connection_id = @@spid;
COMMIT;
CREATE TABLE rroad_progress_messages_requested (
requested_by_connection_id INTEGER NOT NULL PRIMARY KEY );
I. 07/28 11:14:36. 2011-07-28 11:14:36.180 DATA UPGRADE: Updating Foxhound Monitor connection-level sample rows.
I. 07/28 11:14:44. Cache size adjusted to 3648208K
I. 07/28 11:15:00. Cache size adjusted to 3773872K
I. 07/28 11:15:05. Cache size adjusted to 3814120K
I. 07/28 11:15:09. Cache size adjusted to 3828376K
I. 07/28 11:15:11. Cache size adjusted to 3842344K
I. 07/28 11:15:21. Cache size adjusted to 3849032K
I. 07/28 11:15:26. Cache size adjusted to 3851152K
I. 07/28 11:15:27. 1% updated (67219 rows of 6133762)
I. 07/28 11:15:31. Cache size adjusted to 3851888K
I. 07/28 11:15:36. 2% updated (127610 rows of 6133762)
I. 07/28 11:15:36. Cache size adjusted to 3852120K
I. 07/28 11:15:41. Cache size adjusted to 3851928K
I. 07/28 11:15:45. 3% updated (185549 rows of 6133762)
I. 07/28 11:15:47. Cache size adjusted to 3863232K
I. 07/28 11:15:52. Cache size adjusted to 3866080K
I. 07/28 11:15:55. 4% updated (250198 rows of 6133762)
I. 07/28 11:16:03. 5% updated (309751 rows of 6133762)
I. 07/28 11:16:12. 6% updated (368423 rows of 6133762)
I. 07/28 11:16:24. 7% updated (434508 rows of 6133762)
I. 07/28 11:16:33. 8% updated (492776 rows of 6133762)
I. 07/28 11:16:43. 9% updated (555023 rows of 6133762)
I. 07/28 11:16:52. Cache size adjusted to 3909880K
I. 07/28 11:16:54. 10% updated (618356 rows of 6133762)
I. 07/28 11:17:03. 11% updated (679788 rows of 6133762)
I. 07/28 11:17:12. 12% updated (740038 rows of 6133762)
I. 07/28 11:17:15. Cache size adjusted to 3924104K
I. 07/28 11:17:20. Cache size adjusted to 3928528K
I. 07/28 11:17:22. 13% updated (799102 rows of 6133762)
I. 07/28 11:17:25. Cache size adjusted to 3931472K
I. 07/28 11:17:30. Cache size adjusted to 3933392K
I. 07/28 11:17:32. 14% updated (862614 rows of 6133762)
I. 07/28 11:17:35. Cache size adjusted to 3935112K
I. 07/28 11:17:40. Cache size adjusted to 3941088K
I. 07/28 11:17:42. 15% updated (924157 rows of 6133762)
I. 07/28 11:17:45. Cache size adjusted to 3943656K
I. 07/28 11:17:50. Cache size adjusted to 3948168K
I. 07/28 11:17:51. 16% updated (985534 rows of 6133762)
I. 07/28 11:18:01. 17% updated (1047734 rows of 6133762)
I. 07/28 11:18:09. 18% updated (1105532 rows of 6133762)
I. 07/28 11:18:18. 19% updated (1170862 rows of 6133762)
I. 07/28 11:18:25. 20% updated (1227940 rows of 6133762)
I. 07/28 11:18:34. 21% updated (1296232 rows of 6133762)
I. 07/28 11:18:42. 22% updated (1351509 rows of 6133762)
I. 07/28 11:18:50. 23% updated (1419113 rows of 6133762)
I. 07/28 11:18:50. Cache size adjusted to 3953328K
I. 07/28 11:18:58. 24% updated (1476474 rows of 6133762)
I. 07/28 11:19:07. 25% updated (1540502 rows of 6133762)
I. 07/28 11:19:19. 25% updated (1578351 rows of 6133762)
I. 07/28 11:19:29. 26% updated (1595529 rows of 6133762)
I. 07/28 11:19:41. 27% updated (1662896 rows of 6133762)
I. 07/28 11:19:50. Cache size adjusted to 3934168K
I. 07/28 11:19:51. 28% updated (1722376 rows of 6133762)
I. 07/28 11:20:01. 29% updated (1783204 rows of 6133762)
I. 07/28 11:20:13. 30% updated (1844001 rows of 6133762)
I. 07/28 11:20:23. 31% updated (1905747 rows of 6133762)
I. 07/28 11:20:33. 32% updated (1968430 rows of 6133762)
I. 07/28 11:20:46. 33% updated (2025920 rows of 6133762)
I. 07/28 11:20:51. Cache size adjusted to 3921488K
I. 07/28 11:20:57. 34% updated (2087546 rows of 6133762)
I. 07/28 11:21:08. 35% updated (2147983 rows of 6133762)
I. 07/28 11:21:18. 36% updated (2210031 rows of 6133762)
I. 07/28 11:21:28. 37% updated (2272765 rows of 6133762)
I. 07/28 11:21:38. 38% updated (2334295 rows of 6133762)
I. 07/28 11:21:47. 39% updated (2392202 rows of 6133762)
I. 07/28 11:21:51. Cache size adjusted to 3917520K
I. 07/28 11:22:01. 40% updated (2458832 rows of 6133762)
I. 07/28 11:22:12. 41% updated (2519676 rows of 6133762)
I. 07/28 11:22:17. Cache size adjusted to 3918608K
I. 07/28 11:22:22. Cache size adjusted to 3919096K
I. 07/28 11:22:25. 41% updated (2574924 rows of 6133762)
I. 07/28 11:22:26. 42% updated (2580107 rows of 6133762)
I. 07/28 11:22:27. Cache size adjusted to 3914408K
I. 07/28 11:22:32. Cache size adjusted to 3912736K
I. 07/28 11:22:35. 42% updated (2629137 rows of 6133762)
I. 07/28 11:22:37. Cache size adjusted to 3916120K
I. 07/28 11:22:38. 43% updated (2638896 rows of 6133762)
I. 07/28 11:22:42. Cache size adjusted to 3923840K
I. 07/28 11:22:47. Cache size adjusted to 3928120K
I. 07/28 11:22:51. 44% updated (2704091 rows of 6133762)
I. 07/28 11:22:52. Cache size adjusted to 3930848K
I. 07/28 11:23:01. 45% updated (2760737 rows of 6133762)
I. 07/28 11:23:10. 46% updated (2822995 rows of 6133762)
I. 07/28 11:23:21. 47% updated (2883865 rows of 6133762)
I. 07/28 11:23:32. 48% updated (2949216 rows of 6133762)
I. 07/28 11:23:43. 49% updated (3006036 rows of 6133762)
I. 07/28 11:23:55. 50% updated (3073329 rows of 6133762)
I. 07/28 11:24:05. 51% updated (3130900 rows of 6133762)
I. 07/28 11:24:16. 52% updated (3190512 rows of 6133762)
I. 07/28 11:24:27. 53% updated (3255993 rows of 6133762)
I. 07/28 11:24:37. 54% updated (3317650 rows of 6133762)
I. 07/28 11:24:45. 55% updated (3373726 rows of 6133762)
I. 07/28 11:24:56. 56% updated (3441046 rows of 6133762)
I. 07/28 11:25:06. 57% updated (3499829 rows of 6133762)
I. 07/28 11:25:17. 58% updated (3561681 rows of 6133762)
I. 07/28 11:25:22. Cache size adjusted to 4039144K
I. 07/28 11:25:27. 59% updated (3619535 rows of 6133762)
I. 07/28 11:25:39. 60% updated (3683934 rows of 6133762)
I. 07/28 11:25:52. 61% updated (3747029 rows of 6133762)
I. 07/28 11:26:03. 62% updated (3809460 rows of 6133762)
I. 07/28 11:26:11. 63% updated (3864864 rows of 6133762)
I. 07/28 11:26:19. 64% updated (3929201 rows of 6133762)
I. 07/28 11:26:22. Cache size adjusted to 4097008K
I. 07/28 11:26:28. 65% updated (3987744 rows of 6133762)
I. 07/28 11:26:34. Starting checkpoint of "new_f" (foxhound1.db) at Thu Jul 28 2011 11:26
I. 07/28 11:27:22. Cache size adjusted to 4144584K
I. 07/28 11:28:26. Finished checkpoint of "new_f" (foxhound1.db) at Thu Jul 28 2011 11:28
I. 07/28 11:28:32. 66% updated (4049736 rows of 6133762)
I. 07/28 11:28:41. 67% updated (4111378 rows of 6133762)
I. 07/28 11:28:50. 68% updated (4171434 rows of 6133762)
I. 07/28 11:28:58. 69% updated (4233962 rows of 6133762)
I. 07/28 11:29:07. 70% updated (4297422 rows of 6133762)
I. 07/28 11:29:16. 71% updated (4359568 rows of 6133762)
I. 07/28 11:29:22. Cache size adjusted to 4156480K
I. 07/28 11:29:24. 72% updated (4416568 rows of 6133762)
I. 07/28 11:29:34. 73% updated (4480383 rows of 6133762)
I. 07/28 11:29:43. 74% updated (4543735 rows of 6133762)
I. 07/28 11:29:52. 75% updated (4603354 rows of 6133762)
I. 07/28 11:30:01. 76% updated (4669403 rows of 6133762)
I. 07/28 11:30:08. 77% updated (4726151 rows of 6133762)
I. 07/28 11:30:14. Starting checkpoint of "new_f" (foxhound1.db) at Thu Jul 28 2011 11:30
I. 07/28 11:30:22. Cache size adjusted to 4159456K
I. 07/28 11:30:23. Finished checkpoint of "new_f" (foxhound1.db) at Thu Jul 28 2011 11:30
I. 07/28 11:30:26. 78% updated (4791562 rows of 6133762)
I. 07/28 11:30:34. 79% updated (4848418 rows of 6133762)
I. 07/28 11:30:39. Cache size adjusted to 4160200K
I. 07/28 11:30:44. 80% updated (4910819 rows of 6133762)
I. 07/28 11:30:44. Cache size adjusted to 4160384K
I. 07/28 11:30:52. 81% updated (4968486 rows of 6133762)
I. 07/28 11:31:01. 82% updated (5034257 rows of 6133762)
I. 07/28 11:31:10. 83% updated (5098073 rows of 6133762)
I. 07/28 11:31:18. 84% updated (5156062 rows of 6133762)
I. 07/28 11:31:26. 85% updated (5218284 rows of 6133762)
I. 07/28 11:31:34. 86% updated (5275652 rows of 6133762)
I. 07/28 11:31:44. 87% updated (5337384 rows of 6133762)
I. 07/28 11:31:52. 88% updated (5403349 rows of 6133762)
I. 07/28 11:32:00. 89% updated (5460098 rows of 6133762)
I. 07/28 11:32:09. 90% updated (5526121 rows of 6133762)
I. 07/28 11:32:17. 91% updated (5585565 rows of 6133762)
I. 07/28 11:32:24. 92% updated (5643851 rows of 6133762)
I. 07/28 11:32:33. 93% updated (5708012 rows of 6133762)
I. 07/28 11:32:42. 94% updated (5766534 rows of 6133762)
I. 07/28 11:32:50. 95% updated (5829575 rows of 6133762)
I. 07/28 11:32:59. 96% updated (5891464 rows of 6133762)
I. 07/28 11:33:08. 97% updated (5952045 rows of 6133762)
I. 07/28 11:33:18. 98% updated (6018117 rows of 6133762)
I. 07/28 11:33:26. 99% updated (6073883 rows of 6133762)
I. 07/28 11:33:37. 100% updated (6133762 rows of 6133762)
I. 07/28 11:33:47. 70% committed (4313700 rows of 6133762)
I. 07/28 11:33:48. 2011-07-28 11:33:48.717 DATA UPGRADE: Creating foreign keys.
"It's harder to read code than to write it."- Things You Should Never Do, Part I by Joel Spolsky in Joel on Software on Thursday, April 06, 2000
Netscape 6.0 is finally going into its first public beta. There never was a version 5.0. The last major release, version 4.0, was released almost three years ago. Three years is an awfully long time in the Internet world. During this time, Netscape sat by, helplessly, as their market share plummeted.
It's a bit smarmy of me to criticize them for waiting so long between releases. They didn't do it on purpose, now, did they?
Well, yes. They did. They did it by making the single worst strategic mistake that any software company can make:
They decided to rewrite the code from scratch.
. . .
There's a subtle reason that programmers always want to throw away the code and start over. The reason is that they think the old code is a mess. And here is the interesting observation: they are probably wrong. The reason that they think the old code is a mess is because of a cardinal, fundamental law of programming:It's harder to read code than to write it.This is why code reuse is so hard. This is why everybody on your team has a different function they like to use for splitting strings into arrays of strings. They write their own function because it's easier and more fun than figuring out how the old function works.
"I think the way most developers "understand" code is to rewrite it."- When Understanding means Rewriting by Jeff Atwood in Coding Horror on Sep 18, 2006
Did you know that your computer can travel in time? Into the future and backwards?
Here are three reasons SELECT CURRENT TIMESTAMP can suddenly return a value earlier than it did a moment ago:
When the W32Time Manager receives time samples, it uses special algorithms in NTP to determine which of the time samples is the most appropriate for use. The time service also uses another set of algorithms to determine which of the configured time sources is the most accurate. When the time service has determined which time sample is best, based on the above criteria, it adjusts the local clock rate to allow it to converge toward the correct time. If the time difference between the local clock and the selected accurate time sample (also called the time skew) is too large to correct by adjusting the local clock rate, the time service sets the local clock to the correct time. This adjustment of clock rate or direct clock time change is known as clock discipline. - How the Windows Time Service Works
WHILE ... LOOP;
SET t = CURRENT TIMESTAMP;
perform a task that takes a varying amount of time;
SET delay = 5 seconds - DATEDIFF ( between t and CURRENT TIMESTAMP in seconds );
WAITFOR DELAY STRING ( '00:00:', delay );
END LOOP;
DECLARE @from_timestamp TIMESTAMP;
DECLARE @waitfor_msec BIGINT;
DECLARE @waitfor_sec INTEGER;
...
WHILE ... LOOP
...
SET @from_timestamp = CURRENT TIMESTAMP;
CALL rroad_monitor_main();
...
SET @waitfor_msec = 5000 - rroad_f_datediff_msec ( @from_timestamp, CURRENT TIMESTAMP );
IF @waitfor_msec < 1000 THEN
SET @waitfor_sec = 1; -- minimum additional wait, even if this loop pass has taken a long time
ELSE
SET @waitfor_sec = CAST ( ROUND ( CAST ( @waitfor_msec AS DECIMAL ( 11, 2 ) ) / 1000.0, 0 ) AS INTEGER );
END IF;
...
WAITFOR DELAY STRING ( '00:00:', @waitfor_sec );
...
END LOOP;
SQLCODE = -157, SQLSTATE = 53018, ERRORMSG() = Cannot convert '00:00:67' to a timestamp
SET @waitfor_msec = 5000 - ( -62000 ) = 67000
CASE
WHEN @waitfor_msec < 1000 THEN
SET @waitfor_sec = 1; -- minimum additional wait, even if this loop pass has taken a long time
WHEN @waitfor_msec > 5000 THEN
SET @waitfor_sec = 1; -- deal with the fact CURRENT TIMESTAMP can move backwards
ELSE
SET @waitfor_sec = CAST ( ROUND ( CAST ( @waitfor_msec AS DECIMAL ( 11, 2 ) ) / 1000.0, 0 ) AS INTEGER );
END CASE;
Discover Sybase's new cloud data platform, code-named "Fuji", designed specifically for the needs of the ISV market. Many of the recent cloud data platforms have been focused on end-users and providing "infinite" scalability of a single database. "Fuji" is different. "Fuji" is focused on the ISV and providing scalability for the number of databases in the system. Come learn about how "Fuji" will allow a small team to host tens-of-thousands of separate, isolated databases in a secure, flexible, and manageable multi-tenant environment.
Looking for something to do this afternoon? Try dilbert.com...
Here are the latest numbers from Quantcast...
That quote caught my eye during my protracted struggle with 32-versus-64-bits.
"... data types are the key to success."Beyond Windows XP: Get Ready Now for the Upcoming 64-Bit Version of Windows by Stan Murawski, from the November 2001 issue of MSDN Magazine.
Yes, he's talking about C code, but nevertheless data types ARE one of the keys to success. It is all well and good to use abstract data types like "string" and "number" but if you don't have a clue about what they actually are, you may be unprepared when reality intrudes.
SUMMARY In this article the author modifies an industry standard middle-tier application server benchmark called Nile. The goal was to get it to build and run correctly on the 64-bit edition of the Microsoft .NET Advanced Server running on computers with Intel Itanium processors and still build as a 32-bit version to run on Pentium class x86 processors.
While modifying Nile, the author discovered some of the tips he presents here. As the article explains, when modifying code for 64-bit Windows, data types are the key to success. The article discusses which types to use and when, along with new data types and the importance of memory alignment.
The earlier Stupid Error Messages began with this rant:
Have you ever seen an error message like this one?Maybe this one?Invalid phone number (212) 555-1284 - not numericBoth messages are stupid, stupid, stupid... that's three "stupids" out of a maximum possible score of 5. Modern systems should be able to deal with human-readable input formats like credit card numbers with or without the dashes.Invalid phone number 2125551284 - format not (999) 999-999Invalid credit card number 4533-3048-3842-9544 - not numeric
The three asterisks "***" indicate what's new about this posting.
Only the latest point releases of the three supported versions are shown here: 12.0.1, 11.0.1 and 10.0.1.
To find out what you're running just do SELECT @@VERSION
Current builds...
HP-UX Itanium 11.0.1.2584 EBF 07 Apr 2011
10.0.1.3777 EBF 14 Oct 2008
HP-UX PA-RISC 10.0.1.3778 EBF 16 Oct 2008
IBM AIX 12.0.1 GA Upgrade from 12.0.0 15 Mar 2011
11.0.1.2584 EBF 07 Apr 2011
Linux Itanium 10.0.1.3777 EBF 14 Oct 2008
Linux x86/x64 12.0.1.3311 EBF 01 Apr 2011
11.0.1.2617 EBF 13 Jun 2011
10.0.1.4239 EBF 17 Jun 2011
Mac OS 12.0.1.3352 EBF 26 May 2011
11.0.1.2449 EBF 29 Jun 2010
10.0.1.4042 EBF 01 Oct 2010
NetWare 10.0.1.4036 EBF 10 Mar 2010
Solaris SPARC 12.0.1 GA Upgrade from 12.0.0 15 Mar 2011
11.0.1.2632 EBF *** 07 Jul 2011 ***
10.0.1.4239 EBF 17 Jun 2011
Solaris x64 11.0.1.2584 EBF 07 Apr 2011
10.0.1.3870 EBF 01 Apr 2009
Windows CE 10.0.1.4036 EBF 09 Mar 2010
Windows Itanium 10.0.1 GA Upgrade from 10.0.0 26 Apr 2007
Windows x86/x64 12.0.1.3389 EBF *** 11 Jul 2011 ***
11.0.1.2634 EBF *** 14 Jul 2011 ***
10.0.1.4239 EBF 17 Jun 2011
on Virto "Worfklow".
Here is the context...
"95 percent of all programmers think they are in the top 5 percent, and the rest are certain they are above average"- Linus Torvalds, quoted in The One-second War (What Time Will You Die?) by Poul-Henning Kamp, acmqueue, April 6, 2011
If Mr. Torvalds is correct, he is only approximately so: I regard myself a below-average programmer and therefore I fall outside "the rest". If I was above average I would not have to work so hard to produce good code.
"But Linus' [Torvalds] observation that "95 percent of all programmers think they are in the top 5 percent, and the rest are certain they are above average" should not be taken lightly: very few programmers have any idea what the difference is between "wall-clock time" and "interval time," and leap seconds are way past rocket science for them. (For example, Posix defines only a pthread_cond_timedwait(), which takes wall-clock time but not an interval-time version of the call.)"
Whenever a developer starts the Foxhound build process, this exhortation appears:
Here's what it's saying: Go to this page in Foxhound and check to see if there are any run-time error messages that need to be dealt with:
Here's the code that produces the exhortation:
ECHO OFF
ECHO *************************************************************************
ECHO *****
ECHO ***** Have you looked at Foxhound Options - Display Exceptions?
ECHO *****
ECHO ***** Before you rebuild your Foxhound database and wipe out what was in
ECHO ***** the old copy, you might want to see if there were any errors you
ECHO ***** need to look at... or at least copy-and-paste into your to-do list.
ECHO *****
ECHO *************************************************************************
ECHO ON
PAUSE
ECHO OFF
"%SQLANY12%\bin64\dbisql.com"^
-c "ENG=foxhound1;DBN=f;UID=ADHOC;PWD=SQL"^
-q^
CREATE VARIABLE rc INT; SET rc = 0; IF EXISTS ( SELECT * FROM rroad_exception ) THEN SET rc = 999 ENDIF; EXIT rc;
ECHO ERRORLEVEL = %ERRORLEVEL%
IF %ERRORLEVEL% == 999 ( ECHO rroad_exception is known to have rows ) ELSE ( ECHO rroad_exception is not known to have any rows )
PAUSE
Note: The Windows documentation of the IF command talks a bit about %ERRORLEVEL% versus ERRORLEVEL, but it doesn't actually show an example of how IF %ERRORLEVEL% is so much easier think about, code and read than the old-fashioned IF ERRORLEVEL... folks who code batch files for a living know what I'm talkin' about.Here's what the batch file displays in all three cases, rc = 999, 0 and 9:
"%SQLANY12%\bin64\dbisql.com"^
-c "ENG=foxhound1;DBN=f;UID=ADHOC;PWD=SQL"^
-q^
CREATE VARIABLE rc INT; SET rc = 0; IF EXISTS ( SELECT * FROM rroad_exception ) THEN SET rc = 999 ENDIF; EXIT rc;
IF %ERRORLEVEL% == 999 ( GOTO rroad_exception_is_known_to_have_rows ) ELSE ( GOTO rroad_exception_is_not_known_to_have_any_rows )
:rroad_exception_is_known_to_have_rows
ECHO OFF
ECHO *************************************************************************
ECHO *****
ECHO ***** The rroad_exception table is NOT EMPTY !!!
ECHO *****
ECHO ***** Before you rebuild your Foxhound database and wipe out what was in
ECHO ***** the old copy, you might want to see if there were any errors you
ECHO ***** need to look at... or at least copy-and-paste into your to-do list.
ECHO *****
ECHO *************************************************************************
ECHO ON
PAUSE
:rroad_exception_is_not_known_to_have_any_rows
It is a fundamental rule of The MobiLink Synchronization Doctrine that uploaded changes are processed as a single all-or-nothing transaction on the consolidated database.Here's a clue:
"The MobiLink server incorporates changes uploaded from each MobiLink client into the consolidated database in one transaction. It commits these changes once it has completed inserting new rows, deleting old rows, making updates, and resolving any conflicts."OK, true or false?- Transactions in the synchronization process
"When you use -tu, you create a transactional upload: dbmlsync uploads each transaction on the remote database as a distinct transaction. The MobiLink server applies and commits each transaction separately when it is received."- dbmlsync -tu option
"c:\Program Files\Microsoft SQL Server\100\Tools\Binn\osql.exe"^
-d master^
-i "s1_create_and_set_up_cons.sql"^
-I^
-P j68Fje9#fyu489^
-S localhost^
-U sa
PAUSE
---------------------------------------------------------------------
-- Create separate database "mltest" (change the paths as desired).
USE master
GO
CREATE DATABASE mltest
ON
( NAME = mltest,
FILENAME = 'D:\data\mltest\mltest.mdf',
SIZE = 100MB )
LOG ON
( NAME = mltest_log,
FILENAME = 'D:\data\mltest\mltest.ldf',
SIZE = 100MB )
GO
---------------------------------------------------------------------
USE mltest
GO
SET QUOTED_IDENTIFIER ON
GO
---------------------------------------------------------------------
CREATE TABLE account_balance (
account_number VARCHAR ( 10 ) NOT NULL,
amount DECIMAL ( 15, 2 ) NOT NULL DEFAULT 0,
limit_exceeded VARCHAR ( 1 ) NOT NULL DEFAULT 'N' CHECK ( limit_exceeded IN ( 'Y', 'N' ) ),
PRIMARY KEY ( account_number ) )
GO
---------------------------------------------------------------------
BEGIN TRANSACTION
INSERT account_balance ( account_number ) VALUES ( '100' )
INSERT account_balance ( account_number ) VALUES ( '200' )
INSERT account_balance ( account_number ) VALUES ( '300' )
INSERT account_balance ( account_number ) VALUES ( '400' )
INSERT account_balance ( account_number ) VALUES ( '500' )
INSERT account_balance ( account_number ) VALUES ( '600' )
INSERT account_balance ( account_number ) VALUES ( '700' )
INSERT account_balance ( account_number ) VALUES ( '800' )
INSERT account_balance ( account_number ) VALUES ( '900' )
COMMIT TRANSACTION
GO
---------------------------------------------------------------------
CREATE TRIGGER tru_account_balance ON account_balance AFTER INSERT, UPDATE
AS
BEGIN
-- Flag the row as soon as it exceeds the limit.
UPDATE account_balance
SET account_balance.limit_exceeded = 'Y'
FROM inserted
WHERE account_balance.account_number = inserted.account_number
AND account_balance.limit_exceeded = 'N'
AND account_balance.amount > 5000.00
END
GO
"c:\Program Files\Microsoft SQL Server\100\Tools\Binn\osql.exe"^
-d mltest^
-i "s2_update_cons_to_demonstrate_trigger.sql"^
-I^
-P j68Fje9#fyu489^
-S localhost^
-U sa
PAUSE
-- Example 1: One local transaction, one operation.
BEGIN TRANSACTION
UPDATE account_balance SET amount = amount + 6000.00 WHERE account_number = '100'
COMMIT TRANSACTION
GO
-- Example 2: One local transaction, two operations.
BEGIN TRANSACTION
UPDATE account_balance SET amount = amount + 6000.00 WHERE account_number = '200'
UPDATE account_balance SET amount = amount - 1000.00 WHERE account_number = '200'
COMMIT TRANSACTION
GO
-- Example 3: Two local transactions, one operation each.
BEGIN TRANSACTION
UPDATE account_balance SET amount = amount + 6000.00 WHERE account_number = '300'
COMMIT TRANSACTION
GO
BEGIN TRANSACTION
UPDATE account_balance SET amount = amount - 1000.00 WHERE account_number = '300'
COMMIT TRANSACTION
GO
"c:\Program Files\Microsoft SQL Server\100\Tools\Binn\osql.exe"^
-d mltest^
-e^
-q "SELECT * FROM account_balance ORDER BY account_number"^
-I^
-P j68Fje9#fyu489^
-S localhost^
-U sa
SELECT * FROM account_balance ORDER BY account_number
account_number amount limit_exceeded
-------------- ----------------- --------------
100 6000.00 Y
200 5000.00 Y
300 5000.00 Y
400 .00 N
500 .00 N
600 .00 N
700 .00 N
800 .00 N
900 .00 N
(9 rows affected)
1>
"c:\Program Files\Microsoft SQL Server\100\Tools\Binn\osql.exe"^
-d mltest^
-i "%SQLANY11%\MobiLink\setup\syncmss.sql"^
-I^
-P j68Fje9#fyu489^
-S localhost^
-U sa
PAUSE
"c:\Program Files\Microsoft SQL Server\100\Tools\Binn\osql.exe"^
-d mltest^
-i "s5_set_up_MobiLink_scripts_on_cons.sql"^
-I^
-P j68Fje9#fyu489^
-S localhost^
-U sa
PAUSE
USE mltest
GO
SET QUOTED_IDENTIFIER ON
GO
---------------------------------------------------------------------
EXECUTE ml_add_column 'v1', 'account_balance', NULL, NULL
GO
EXECUTE ml_add_column 'v1', 'account_balance', 'account_number', NULL
GO
EXECUTE ml_add_column 'v1', 'account_balance', 'amount', NULL
GO
---------------------------------------------------------------------
EXECUTE ml_add_table_script 'v1', 'account_balance', 'upload_insert', NULL
GO
EXECUTE ml_add_table_script 'v1', 'account_balance', 'upload_insert', '
INSERT account_balance
( account_number,
amount )
VALUES ( {ml r.account_number},
{ml r.amount} )'
GO
---------------------------------------------------------------------
EXECUTE ml_add_table_script 'v1', 'account_balance', 'upload_update', NULL
GO
EXECUTE ml_add_table_script 'v1', 'account_balance', 'upload_update', '
UPDATE account_balance
SET amount = {ml r.amount}
WHERE account_number = {ml r.account_number}'
GO
---------------------------------------------------------------------
EXECUTE ml_add_table_script 'v1', 'account_balance', 'upload_delete', NULL
GO
EXECUTE ml_add_table_script 'v1', 'account_balance', 'upload_delete', '
DELETE account_balance
WHERE account_number = {ml r.account_number}'
GO
"%SQLANY11%\bin32\dbinit.exe"^
remo.db
"%SQLANY11%\bin32\\dbspawn.exe"^
-f "%SQLANY11%\bin32\dbeng11.exe"^
-o dbeng11_log_remo.txt^
-x tcpip^
remo.db
"%SQLANY11%\bin32\dbisql.com"^
-c "ENG=remo;DBN=remo;UID=dba;PWD=sql"^
READ ENCODING Cp1252 "s6_create_and_set_up_remo.sql"
PAUSE
CREATE TABLE account_balance (
account_number VARCHAR ( 10 ) NOT NULL,
amount DECIMAL ( 15, 2 ) NOT NULL DEFAULT 0,
PRIMARY KEY ( account_number ) )
GO
---------------------------------------------------------------------
INSERT account_balance ( account_number ) VALUES ( '400' );
INSERT account_balance ( account_number ) VALUES ( '500' );
INSERT account_balance ( account_number ) VALUES ( '600' );
INSERT account_balance ( account_number ) VALUES ( '700' );
INSERT account_balance ( account_number ) VALUES ( '800' );
INSERT account_balance ( account_number ) VALUES ( '900' );
COMMIT;
---------------------------------------------------------------------
CREATE PUBLICATION p1 (
TABLE account_balance ( account_number,
amount ) );
CREATE SYNCHRONIZATION USER "1" TYPE tcpip;
CREATE SYNCHRONIZATION SUBSCRIPTION TO p1 FOR "1";
"%SQLANY11%\bin32\dbisql.com"^
-c "ENG=remo;DBN=remo;UID=dba;PWD=sql"^
READ ENCODING Cp1252 "s7_update_remo_to_demonstrate_dbmlsync_without_tu.sql"
PAUSE
-- Example 4: One synchronization without -tu, one transaction, one operation.
UPDATE account_balance SET amount = amount + 6000.00 WHERE account_number = '400';
COMMIT;
-- Example 5: One synchronization without -tu, one transaction, two operations.
UPDATE account_balance SET amount = amount + 6000.00 WHERE account_number = '500';
UPDATE account_balance SET amount = amount - 1000.00 WHERE account_number = '500';
COMMIT;
-- Example 6: One synchronization without -tu, two transactions, one operation each.
UPDATE account_balance SET amount = amount + 6000.00 WHERE account_number = '600';
COMMIT;
UPDATE account_balance SET amount = amount - 1000.00 WHERE account_number = '600';
COMMIT;
SELECT * FROM account_balance ORDER BY account_number;
account_number amount
--------------------------------
400 6000.00
500 5000.00
600 5000.00
700 0.00
800 0.00
900 0.00
(6 rows)
"%SQLANY11%\bin32\mlsrv11.exe"^
-c "DSN=mltest;UID=sa;PWD=j68Fje9#fyu489"^
-fr^
-o mlsrv11_log_cons.txt^
-os 10M^
-ppv 60^
-vcefhimnopqrstu^
-zu+
"%SQLANY11%\bin32\dbmlsync.exe"^
-c "ENG=remo;DBN=remo;UID=dba;PWD=sql"^
-e "adr='host=localhost';sv=v1"^
-o dbmlsync_log_remo_from_step_9.txt^
-os 10M^
-uo^
-vnorsu^
-x
SELECT * FROM account_balance ORDER BY account_number
account_number amount limit_exceeded
-------------- ----------------- --------------
100 6000.00 Y
200 5000.00 Y
300 5000.00 Y
400 6000.00 Y
500 5000.00 N
600 5000.00 N
700 .00 N
800 .00 N
900 .00 N
(9 rows affected)
1>
"%SQLANY11%\bin32\dbisql.com"^
-c "ENG=remo;DBN=remo;UID=dba;PWD=sql"^
READ ENCODING Cp1252 "s10_update_remo_to_demonstrate_dbmlsync_tu.sql"
PAUSE
-- Example 7: One synchronization with -tu, one transaction, one operation.
UPDATE account_balance SET amount = amount + 6000.00 WHERE account_number = '700';
COMMIT;
-- Example 8: One synchronization with -tu, one transaction, two operations.
UPDATE account_balance SET amount = amount + 6000.00 WHERE account_number = '800';
UPDATE account_balance SET amount = amount - 1000.00 WHERE account_number = '800';
COMMIT;
-- Example 9: One synchronization with -tu, two transactions, one operation each.
UPDATE account_balance SET amount = amount + 6000.00 WHERE account_number = '900';
COMMIT;
UPDATE account_balance SET amount = amount - 1000.00 WHERE account_number = '900';
COMMIT;
SELECT * FROM account_balance ORDER BY account_number;
account_number amount
--------------------------------
400 6000.00
500 5000.00
600 5000.00
700 6000.00
800 5000.00
900 5000.00
(6 rows)
"%SQLANY11%\bin32\dbmlsync.exe"^
-c "ENG=remo;DBN=remo;UID=dba;PWD=sql"^
-e "adr='host=localhost';sv=v1"^
-o dbmlsync_log_remo_from_step_11.txt^
-os 10M^
-tu^
-uo^
-vnorsu^
-x
SELECT * FROM account_balance ORDER BY account_number
account_number amount limit_exceeded
-------------- ----------------- --------------
100 6000.00 Y
200 5000.00 Y
300 5000.00 Y
400 6000.00 Y
500 5000.00 N
600 5000.00 N
700 6000.00 Y
800 5000.00 N
900 5000.00 Y
(9 rows affected)
1>
PAUSE Are you sure you want to drop the consolidated database?
"c:\Program Files\Microsoft SQL Server\100\Tools\Binn\osql.exe"^
-d master^
-i "s12_drop_cons.sql"^
-I^
-P j68Fje9#fyu489^
-S localhost^
-U sa
PAUSE
USE master
GO
BEGIN TRY
DROP DATABASE mltest
END TRY
BEGIN CATCH
-- ignore error
END CATCH
GO
PAUSE Are you sure you want to delete all the files?
"%SQLANY11%\bin32\dbstop.exe" -c "ENG=remo;DBN=remo;UID=dba;PWD=sql" -y
PAUSE Wait a bit, then
ERASE /F *.log
ERASE /F dbeng11_log_remo.txt
ERASE /F dbmlsync_log_remo*.txt
ERASE /F mlsrv.mle
ERASE /F mlsrv11_log_cons.txt
ERASE /F remo.db
ERASE /F remo.rid
PAUSE