Wednesday, April 19, 2017

Finding currently executing queries and parameters

If you've worked with an Object Relational Mapper (ORM) such as Hibernate, NHibernate, Entity Framework, etc., then you'll know these sometimes convert your queries into parameterized queries that can become quite beastly.

Trying to debug it means either profiling the database to see what queries are executing, and then seeing the query and values from there, or if you can't profile it, maybe selecting from some system tables to do a similar thing.

This snippet below (thanks again StackOverflow) will give you some nice details about the queries on a database, including an XML query plan that contains the parameters that were used when generating the query plan. It can be useful in diagnosing slow queries:

select * 
from sys.dm_exec_requests r 
cross apply sys.dm_exec_query_plan(plan_handle) as qp
cross apply sys.dm_exec_sql_text(r.sql_handle) 
where r.database_id = DB_ID('<dbname>') 

Thursday, March 23, 2017

tail on Windows with PowerShell

One of the well known Unix/Linux commands is tail, which gets the tail of a file, meaning the end of a file and prints it out to the output stream.

I used to try find nice programs for this, including Baretail which has some very nice features like colouring lines in that match certain patterns etc.

But if you just want a simple, and now built into Windows solution, just use PowerShell:

Get-Content -Tail 10 filename.txt

This will show the last 10 lines of the file. You can even follow the tail, or watch it for changes, as below:

gc -Tail 10 -Wait filename.txt

Another nice thing you can do is then pipe this into Select-String to filter the output:

gc -Tail 10 -Wait filename.txt | Select-String -Pattern somepattern

Monday, March 20, 2017

diff PDF files

At a client we have a PDF template that needs to be used for registering users. When this is updated, the template is overriden. But it would be nice to be able to easily see what changed between the two.

Well, this is possible :)

You can use Imagemagick and Ghostscript to do this.

You should be able to just do the below:

magick compare old.pdf new.pdf diff.pdf

But that didn't seem to work well. What seems to work better is to rather convert the PDF to an image first, and then compare each page.

magick convert -density 300 -quality 100 old.pdf old.png
magick convert -density 300 -quality 100 new.pdf new.png

magick compare old-0.png new-0.png diff-0.png

Depending on the options you can get better or worse results. Changing the colorspace to CMYK for example could yield better results, or maybe using options to blur/sharpen/despeckle the image too. Try play around with the options to see better results.

The best results I had was actually via using Adobe Acrobat to first export the PDF to images, and then run the compare. I still need to figure out why, because unfortunately I only have the license at work, so this won't always be an option. I'll hopefully update this post in future to show my favourite variation :)

Tuesday, February 21, 2017

Modern Database Development Practices

Back in November 2012 I presented on this topic at Entelect's Dev Days.

I've also done a blog post previously on setting up Flyway.

I keep referring back to the same links and concepts and this post is here just for that, as a pointer to good resources and brief points about this topic.

I may revisit it and put down my own consolidated content, but for now this will do.

Wednesday, February 15, 2017

C# - Testing that different cultures won't affect formatting

Ever worked on a system where you write code and test it and it all works perfect, but then maybe a unit test starts failing on a build server, or maybe a report looks wrong to the consumers of the report, all because it formatted a number to "12345,67" instead of "12345.67"?

This tip will help you.

First, lets assume we have this code:

public class ReportFormatter
  public string Format(decimal value)
    return value.ToString();

And a nice little unit test for it:

public sealed class ReportFormatterTest
  public void Format()
    var sut = new ReportFormatter();
    var result = sut.Format(12345.67M);
    Assert.AreEqual("12345.67", result);

This works perfectly fine. Lets even imagine that all our machines all have the same setup, and all are set to use the same regional settings. Great, nothing should ever break.

Until maybe Microsoft releases a patch to Windows that changes our regional settings to be "correct" - in fact, South Africa should be using a comma as a separator... even though none of us use this standard :D

So then it breaks our code, and our business rules that disagree with it.

Well, the good news is we can change the regional settings of the running thread, by changing its CultureInfo details. Here is a little utility class to do so:

public class TemporaryCultureSwitch : IDisposable
  private readonly CultureInfo _originalCulture;
  private readonly CultureInfo _originalUICulture;
  public TemporaryCultureSwitch(CultureInfo cultureInfo)
    _originalCulture = Thread.CurrentThread.CurrentCulture;
    _originalUICulture = Thread.CurrentThread.CurrentUICulture;
    Thread.CurrentThread.CurrentCulture = cultureInfo;
    Thread.CurrentThread.CurrentUICulture = cultureInfo;
  public TemporaryCultureSwitch(string cultureName) : this(new CultureInfo(cultureName)) { }
  public void Dispose()
    Thread.CurrentThread.CurrentCulture = _originalCulture;
    Thread.CurrentThread.CurrentUICulture = _originalUICulture;

We can now update our test to be a bit more specific:

public void FormatShouldNotBeAffectedByCultureChanges()
  var culture = new CultureInfo("en-ZA");
  culture.NumberFormat.NumberDecimalSeparator = ",";
  using (new TemporaryCultureSwitch(culture))
    var sut = new ReportFormatter();
    var result = sut.Format(12345.67M);
    Assert.AreEqual("12345.67", result);

Now we have a test that will fail consistently! Time to fix the code. One way of doing this is realizing that there is an overload of Decimal.ToString that takes in a CultureInfo object. We actually can use the InvariantCulture as below:

public string Format(decimal value)
  return value.ToString(CultureInfo.InvariantCulture);

The test passes and we now know for sure that regional settings won't affect our code.