Friday, July 14, 2017

The Wonder of Chicken!

I follow a blog called French Letters, by  a lady from a town near Nîmes, and a couple of posts ago she described how she'd got addicted to a particular chicken dish. So, I decided to try it out.

I should warn you that while this is really easy,
a. it has peanuts
b. no pictures until next time - it was so good we scarfed it all down!

You'll need alarge frying pan and an oven pot, such as a Pyrex or Arcopol glass bowl with a flat base and lid (I used an arcopol 26).
So, to start, there's two parts that come together during the process.

1. The Meat.
2. The Gravy

The Meat
This was chicken. She used thighs, but I used two chicken breasts double cut to make four thin pieces.
Preparation here is simple; heat maybe two or three tablespoons of oil in a large pan and fry the chicken on each side until it's cooked and browned just a bit. The first couple of times you turn it, sprinkle a little salt over the top before the turn, so it heats and melts and flavours the meat as it heats up.
When the chicken pieces are done place them flat in the bottom of your oven-proof dish.
Turn your oven on to 350F.

At this point I started rice in my rice cooker; you have just enough time to do this and have it be ready when the dish emerges from the oven.

The Gravy
The ingredients are these:

Diced Red Bell Pepper         1 tsp Cinnamon     
Chopped Cilantro 1 tsp Paprika
Chopped Spring Onions 2 tsp Ginger
Peanut Butter A little Salt
1 can of Coconut Milk Pepper to taste.

I used a bunch of eight small Spring Onions and chopped them completely (excepting the roots and dried tips, of course!). I used a small box of Cilantro from the supermarket and one really large but very firm red Bell Pepper.
Using the oil left in the pan after the chicken has been cooked, add the vegetables and fry them for about 3-4 minutes until they begin to wilt. Then add the spices (right-hand column) and stir them in to the frying vegetables. After a minute or so, add two good dollops of peanut butter and then the Coconut milk. Mix all the ingredients well, stirring so that the peanut butter mixes in to the cocout milk.
Pour this mixture over the chicken breasts in the pot
Cover the pot and cook in the oven for about 25 minutes.

Remove pot from oven, uncover, and let it start to cool.

At this point my rice was cooked, so I could fill plates with beds of rice.

Plate your masterpiece, serve, and bask in the applause from your family and guests.


Tuesday, June 13, 2017

That Scenery Keeps Changing!

Wow, but does it ever!
Being a consultant certainly takes you places!
So far I was in Dearborn long enough to make friends with people and get to know the place. I even took the short route from there to Rochester for SQL Saturday by driving along the north coast of Lake Erie (the Canadian side) and back! Then the budget ran out and it was time to leave.

Of course we had just moved to where my wife's "sudden" family lives - Tacoma - and bought a little house, even! It's nice, although they might have thought of adding a few inches here and there (sometimes I go to bed with a headache!)

So we've been here almost a month and a half now, but I've actually been here about 12 days! I've worked in Montvale (NJ), Santa Monica, Beverley Hills, and Mountain View (all CA) since I came here! Still, I have to say that it's fun! My only regret is not seeing the friends I've built up over the last six or so years at all the East Coast SQL Saturday events. There are far fewer out here, and they're much farther apart. Anyhow, I've sent an email to the guy who seems to run the local chapter and we'll see.

There's no yummy food this post either, I'm afraid, as the kitchen looks like a down-sizer from the last place, which is going to be rather difficult. One thing I can recommend, though, is that if you find yourself in a Shari's diner, order the pie shake! It's a milk shake with pie blent in too! Yummy!!!


Friday, December 09, 2016

An email I got from my favourite PC Maker!

Guess what System-76 sent me ... some code!!

michael@system76-computer:~$ sudo apt upgrade
[sudo] password for michael:
Package: laptops-desktops
Laptops calculating price... Done
    Lemur/Gazelle/Kudu: up to $155 off
    Oryx Pro: up to $265
    Serval/Bonobo: up to $285 off
Desktops calculating price... Done
    Meerkat: up to $155 off
    Sable/Wild Dog/Leopard: up to $130 off
    Silverback: up to $390 off

Description-en: This is a "System76 sale description" package. Powerful linux machines are on sale now. Plus you can receive an even greater discount depending on your component upgrade.

Do you want to continue? [Y/n]

Yeah - this reads like an advert - their advert! However, as the very happy owner of a System-76 Bonobo since November 2011 - a machine that is still among the fastest I have ever seen - I'm happy to recommend their computers - and take not one ha'penny for it!


Tuesday, October 25, 2016

A Change of Scenery!

It's been a while since I set finger to keyboard here - naughty me! - but that should change soon - I promise!

After a rather insanely busy first six months of the year - fun but busy - I took a deep breath, strapped all my knowledge about me, jumped ship, and was happy to be rescued by a passing mega-vessel! IOW, I've changed jobs (again), and am now a consultant for no less a company than Microsoft !

No, that doesn't mean that I'm moving to Washington or Oregon, much to the AG's bitter disappointment. Right now it means that during the week I'm to be found on the sunny Costa del Erie, on the beaches at Dearborn, helping out at a well-known purveyor of mobile goods that can be any colour so long as they're black!

Tech Tip for the Episode

If you're getting problems assigning new identities because it takes too long to determine whether you want a new one or just to find the one already in use, then try casting your mind back to Comp Sci 102 and principles of Operating Systems and Mutual Exclusion (mutex). After that horrifying excursion, jump here. You are probably familiar with locking rows or pages of data: these (Application Locks) are simply a lock on a word in memory, so are lots faster. They'll die if you restart SQL Server (of course!) and also when your process (spid) closes, so the memory gets released. They have a name, too, so you can do fun things like naming them according to the data you're trying to lock, thus creating locking without touching the table ...

Have fun!


Monday, August 15, 2016

What Broke, for Heavens' Sake?!

[Warning: SQL Tech !]
Well, so you're working (like me) with Microsoft's SQL Server and you've got all this code, and every now and then it breaks. Usually because some crazy user did something dumb like put a tick ( ' ) in the middle of a text field, like they've been instructed not to do, or managed to add something like a hidden character, or whatever.
Anyhow, the code breaks, and the carefully crafted error trapping works perfectly, so you know the line of the procedure that it died on, and a fairly generic and opaque description of the problem itself.
However, there are two things that you don't know:
1. the actual piece of data that caused the failure
2. the history of the processing of that data up to the point of failure
Knowing the actual data that caused the failure and be a great help; knowing what happened to it on its way to the point of failure can be even a greater eye-opener, especially if you're working with code that you inherited from someone else now long gone.

The obvious way to handle this problem is to add some logging code to your program. Personally, I maintain programs where the data is usually in the form of messages, even when they arrive batched up in a text file, which move through the systems, undergoing one of a number of sequences of operations, depending on where they've come from, what their content is, and where they're going. Each of these messages is assigned a unique ID to identify it on its journey from receipt to emission.
So, I have a log table with these fields:

IDRecord id in the table
CreatedOnDate record was added
SubjectWhat is happening in general
TextDetailed Info about the situation
TrackingIDID of the message being handled
OriginName of the procedure writing the record
SequenceSequence number of call points in procedure

I also have a stored procedure that accepts the fields it needs (the last 5) and inserts a record into the table.
All well and good so far, until you get to the small matter of transactions. Very wonderful things, transactions, and very helpful. Very nice to use to prevent things that have to be done together getting only part-done. Rolling back a transaction allows you to re-try the whole thing again when you know what's going wrong and have fixed the problem. However, the rollback undoes everything the code has written ... including all the logging, so you never get to find out what it was that went wrong - just that it went wrong !

The Light!
This, of course, is not a whole heap of help, but one day I was reading a book on SQL Server and suddenly part of the description of committing (successfully completing a transaction) turned on a light in my head!

COMMIT TRANSACTION makes all data modifications performed since the start of the transaction a permanent part of the database

So if you roll back the transaction, instead of committing it, everything written is rolled back. That's why the records in the log table vanished with a rollback - that much I already understood.
However, what I didn't cotton on to immediately was the implication of the corollary - that things not actually written out are not deleted.
Actually, it was a few lines into a piece of code before something hit me! Variables don't get rolled back - because they're in memory and not written to disc. And what then hit me was that a Table Variable in SQL Server is a Variable - even though it's very often stored in TempDB (on disc!).

The Implementation
So, to keep my logs that will tell me what happened to cause the rollback, I wrote some code to copy the ones for this message out into a table variable of the same structure as my log table, did the rollback, and then stuffed all those saved records back into the log table.

Et Voilà! On trouve tous les donneés intacte!!

The code is like this:

declare @taLogTable ( [Field List] )
insert into @taLogTable
select * from dbo.LogTable where [specify which records I want]
-- ---------------------
rollback transaction
-- ---------------------
set identity_insert dbo.LogTable on
insert into dbo.LogTable ( [Field List] )
select * from @taLogTable where ID not in (select ID from dbo.LogTable)
set identity_insert dbo.LogTable off

But Wait - There's More
That's fine, but there's a small hiccough coming here.
Part one is that the system runs in two separate databases, and we use synonyms to refer to objects in one database from another. That's perfectly fine: if I need to save logging data that's been logged on another machine but is still part of this transaction, I simply use the appropriate synonyms for the tables involved:

declare @taLogTable ([Field List])
insert into @taLogTable
select * from syn_OtherDB_dbo_LogTable where [specify which records I want]
-- ---------------------
rollback transaction
-- ---------------------
set identity_insert syn_OtherDB_dbo_LogTable on
insert into syn_OtherDB_dbo_LogTable ( [Field List])
select * from @taLogTable where ID not in (select ID from syn_OtherDB_dbo_LogTable)
set identity_insert syn_OtherDB_dbo_LogTable off

So I'm using the synonyms obediently, so if I copy the code to a test database, or somewhere similar, where the name of the other database is OtherDB_Test instead of OtherDB then all will still be ok.

Yeah, well, almost. Close, but no cigar! Synonyms are great in SQL Server except that the set identity_insert command (which allows me to push values into a field which otherwise generates its own automatically) doesn't accept synonyms. So, everything has to be explicit, and therefore there's more more worry and work at the time of deployment in a release when you also have to check that all the set identity_insert statements are pointing to the correct databases!

Victory In The End
There is, of course, a way to fix things to avoid this problem (which, if you're bitten by it, probably happens several months after the release and when you've totally forgotten all about it, because it only ever happens with errors, and they really don't happen all that often.

The way to do it is to use a stored procedure instead of the code after the rollback in order to achieve the same result. You pass in to the procedure the name of the database into whose LogTable the data has to return (I called it @strDatabase here), and also the table variable (@taLogTable). Then the code is like this:

declare @strSQL nvarchar(2000)
set @strSQL = 'SET IDENTITY_INSERT ' + @strDatabase + '.dbo.LogTable ON; '
set @strSQL += 'insert into ' + @strDatabase + '.dbo.LogTable'
set @strSQL += '( [Field List] )'
set @strSQL += 'select * from @taLogTable '
set @strSQL += 'where id not in '
set @strSQL += '(select id from ' + @strDatabase + '.dbo.LogTable); '
set @strSQL += 'SET IDENTITY_INSERT ' + @strDatabase + '.dbo.LogTable OFF; '

There is just one little extra piece of code you'll have to incorporate. 
SQL Server needs a type for each object coming in to a stored procedure, so you have to declare a user type for your table variable. This shouldn't be too much of a hardship, especially if you're using the same structure for all your log tables (a very good idea!). The parameters for that procedure turn out to be like this:
@strDatabase varchar(32),
@taLogTable taLogTable readonly

so not such a problem after all, and helps the programmers coming after you!

Have fun - keep cool!   Food next time!