Got Windows 10? Want to tweak a lot of settings in one place?
Create a new folder on your desktop and rename it "GodMode.{ED7BA470-8E54-465E-825C-99712043E01C}"
Happy tweaking
Monday, 4 September 2017
Saturday, 2 September 2017
Installing phonegap developer app on older devices or older versions of the developer app
You may go to the android play store and find that it tells you that the app is incompatible with your device even though you have had it installed on that device before.
Or you may find that you want to install an older version of the developer app because it worked better than the current version in the stores.
Fear not, you can download older versions from here
Or you may find that you want to install an older version of the developer app because it worked better than the current version in the stores.
Fear not, you can download older versions from here
Monday, 5 June 2017
Installing Birt on Linux
This is a simple post of how to install the Birt reporting engine on Linux. In this example I am installing on Linux Mint 18.1 but the same will apply to other versions and distros based on Debian/Ubuntu.
You can use your package manager or the command line apt-get tool.
Step 1: Install Apache2 and Mysql
Apache 2 is the web server of choice for a lot of Linux installations. Mysql is a free database engine. I would assume that these tools would already be installed on your system by the time you wanted to get birt up and running.
$ sudo apt-get install apache2 mysql-server
Step 2: Install Tomcat8
At the time of writing, this is the latest version of Tomcat
$ sudo apt-get install tomcat8
Step 3: Webapps folder
This is generally downloaded from the Birt-eclipse website (http://download.eclipse.org/birt/downloads/#runtime). Unzip the file, the folder we're interested in is the WebViewerExample, you can rename this as you wish and copy or link it under /var/lib/tomcat8/webapps/
Step 4: jdbc driver
For MySQL:
$ sudo apt-get install libmysql-java
For Microsoft SQL Server, download from SourceForge https://sourceforge.net/projects/jtds/, unzip the file, copy the jtds-*.jar file to /var/lib/tomcat8/lib
Step 5 restart birt
$ sudo service tomcat8 restart
Additional Steps
Assuming you're using Eclipse to design the report, you will need to install the mysql driver into that, the download for the jar file is here https://dev.mysql.com/downloads/connector/j/
You can use your package manager or the command line apt-get tool.
Step 1: Install Apache2 and Mysql
Apache 2 is the web server of choice for a lot of Linux installations. Mysql is a free database engine. I would assume that these tools would already be installed on your system by the time you wanted to get birt up and running.
$ sudo apt-get install apache2 mysql-server
Step 2: Install Tomcat8
At the time of writing, this is the latest version of Tomcat
$ sudo apt-get install tomcat8
Step 3: Webapps folder
This is generally downloaded from the Birt-eclipse website (http://download.eclipse.org/birt/downloads/#runtime). Unzip the file, the folder we're interested in is the WebViewerExample, you can rename this as you wish and copy or link it under /var/lib/tomcat8/webapps/
Step 4: jdbc driver
For MySQL:
$ sudo apt-get install libmysql-java
For Microsoft SQL Server, download from SourceForge https://sourceforge.net/projects/jtds/, unzip the file, copy the jtds-*.jar file to /var/lib/tomcat8/lib
Step 5 restart birt
$ sudo service tomcat8 restart
Additional Steps
Assuming you're using Eclipse to design the report, you will need to install the mysql driver into that, the download for the jar file is here https://dev.mysql.com/downloads/connector/j/
Wednesday, 6 January 2016
MySQL Workbench Delimiter gotcha
I found a problem when working with MySQL Workbench and using a delimiter other than the standard semi colon.
The above 700 line SQL script appears to have run without error, only problem is that I have changed the delimiter to "$$" and forgotten to append that after the last statement in the script (create table). Looking closely at the result output you can see that the last statement executed was not the create table one.
So there's one thing to look out for, remember to put the last delimiter in.
The above 700 line SQL script appears to have run without error, only problem is that I have changed the delimiter to "$$" and forgotten to append that after the last statement in the script (create table). Looking closely at the result output you can see that the last statement executed was not the create table one.
So there's one thing to look out for, remember to put the last delimiter in.
Wednesday, 8 July 2015
Enabling remote access for MySQL
When you
install MySQL, only local access is enabled by default. Remote access is
restricted in 2 ways:
In the
config file /etc/mysql/my.cnf
Comment out the bind-address
line:
#bind-address = 127.0.0.1
User access
To enable the ruser from
anywhere, you must use the grant command:
mysql> GRANT ALL PRIVILEGES ON *.* TO
'USERNAME'@'%' IDENTIFIED BY 'PASSWORD' WITH GRANT OPTION;
Replacing 'USERNAME' and password 'PASSWORD' with your own values of course.
After modifying the config file,
you must restart the mysql service:
$ service mysql restart
Don't forget to use
"sudo" (or su) if you're not logged in as root.
Wednesday, 7 May 2014
Internet Explorer startup window position
One of my clients' servers that I log onto remotely had IE9 on it, being the only browser installed on that machine and being as I'm supporting a web based app for them I have no choice but to use such abomination.
I was quite annoyed in the way it always started up in the same position on the screen, quite like a postage stamp on my 1080p screen. Every time I would have to resize the window. I didn't want to maximize it as there are some icons down the left of the screen that I use to launch other things as well and a maximized IE window would cover them up.
I tried all the usual tricks to coax IE to save its window position, pressing Ctrl whilst exiting, pressing Shift whilst exiting all to no avail.
Finally I found this post from Microsoft MVP Don Varnau, basically you need to open a page in a new window, resize that, close the old window then close the new window.
This strikes me as a little odd, as a programmer I know it would take a lot more effort to program this behaviour into a system than it would to simply save the main window position on exit. What the thinking was behind that I'll never know, I can only imagine how that meeting went :-\
I was quite annoyed in the way it always started up in the same position on the screen, quite like a postage stamp on my 1080p screen. Every time I would have to resize the window. I didn't want to maximize it as there are some icons down the left of the screen that I use to launch other things as well and a maximized IE window would cover them up.
I tried all the usual tricks to coax IE to save its window position, pressing Ctrl whilst exiting, pressing Shift whilst exiting all to no avail.
Finally I found this post from Microsoft MVP Don Varnau, basically you need to open a page in a new window, resize that, close the old window then close the new window.
This strikes me as a little odd, as a programmer I know it would take a lot more effort to program this behaviour into a system than it would to simply save the main window position on exit. What the thinking was behind that I'll never know, I can only imagine how that meeting went :-\
Tuesday, 8 April 2014
Local mail in Linux and Mutt
Linux has a local mail system, it probably won't be of much interest to you in terms of day to day email since you probably have email set up with your ISP, Yahoo, Google, etc.
One thing that you may be interested in is administrative alerts that are sent to the root mailbox, invalid password attempts, results of cron jobs, etc.
I found the easiest way to view this mail is to install mutt, I'm currently running Linux Mint 16 but the process detailed below will be the same for other versions, Ubuntu, Debian and their derivatives.
Firstly install mutt:
$ sudo apt-get install mutt
Any time that you want to view root's email just type:
$ sudo mutt
You will then see the root mailbox. You might find your own mailbox is inaccessible, probably because it doesn't exist yet :-) This is easily remedied with a few simple command
Assuming your username is "jones", we create an empty file of that name:
$ sudo touch /var/mail/jones
Then we want to make sure that jones can use it, so assign ownership to yourself:
$ sudo chown jones /var/mail/jones
Now you own, you can change the permission so that only you can use it.
$ chmod 600 /var/mail/jones
Now you can use mutt yourself.
One thing that you may be interested in is administrative alerts that are sent to the root mailbox, invalid password attempts, results of cron jobs, etc.
I found the easiest way to view this mail is to install mutt, I'm currently running Linux Mint 16 but the process detailed below will be the same for other versions, Ubuntu, Debian and their derivatives.
Firstly install mutt:
$ sudo apt-get install mutt
Any time that you want to view root's email just type:
$ sudo mutt
You will then see the root mailbox. You might find your own mailbox is inaccessible, probably because it doesn't exist yet :-) This is easily remedied with a few simple command
Assuming your username is "jones", we create an empty file of that name:
$ sudo touch /var/mail/jones
Then we want to make sure that jones can use it, so assign ownership to yourself:
$ sudo chown jones /var/mail/jones
Now you own, you can change the permission so that only you can use it.
$ chmod 600 /var/mail/jones
Now you can use mutt yourself.
Monday, 7 April 2014
Installing Phonegap on Linux
Installing Phonegap on Linux
Introduction
Phonegap will enable you to write
mobile apps in HTML/CSS/JavaScript and then deploy to multiple mobile targets
including Android and iOS. This document will outline the installation
procedure for Linux Mint. I did this on Linux Mint 16 but the process should be
similar or the same for other versions too. Also, since Linux Mint is based
upon Ubuntu, which in turn is based upon Debian, this may work (or help) on
those distros and derivatives as well. For other flavours of Linux you should
consult the relevant documentation as the overall process will be similar but
the commands for installing programs will be different (e.g. rpm, aptitude and
yum as opposed to apt-get).
You can get this installed on Windows as well, but I found the emulator to run very slowly, even with the HAXM hardware virtualisation.
Install Pre-requisites
There’s a lot, I found this wasn’t
all documented in the same place and I had to Google error messages, etc. to find
solutions.
Install Apache Ant
A Java library and build tool
required by Phonegap.
$ sudo apt-get install ant
Install Java Development SDK (JDK)
The Java Development Kit.
$ sudo apt-get install openjdk-7-jdk
This may change to openjdk-8-jdk in later Linux editions, Linux Mint 18 uses this number.
This may change to openjdk-8-jdk in later Linux editions, Linux Mint 18 uses this number.
Install Android SDK
Download package relevant to your
system. Unzip the file into your home folder, e.g. /home/username/android-sdk-linux
Set up environment
Edit your .bashrc file:
$ gedit ~/.bashrc
Add the lines to point variables
at the installed apps, e.g.
JAVA_HOME=/usr/lib/jvm/default-java
ANDROID_HOME=$HOME/android-sdk-linux
ANDROID_HOME=$HOME/android-sdk-linux
PATH=$PATH:$JAVA_HOME/bin:$ANDROID_HOME/tools
You may need to add your bin
folder to the path as well, it may already be there, if not then add “:$HOME/bin”
to the path, e.g.
if [ -d “$HOME/bin” ] ; then
PATH=$HOME/bin :$PATH
fi
PATH=$HOME/bin :$PATH
fi
Update Android SDKs
Open terminal and run the android
sdk manager:
$ android &
Select packages if required, what
you need should already be selected apart from “Intel x86 Atom System Image”
(this will work better than emulating an ARM chip later), you may want install
earlier versions also. Click the [Install (n) Packages] button. This may take a
while, you’ll probably have time to grow some coffee beans, let alone make a
cup. Luckily, as this is a multitasking operating system, you can go onto the
next step whilst this one is completing. Once complete you may find there are
still some packages to install, click on the [Install (n) Packages] button
again.
Back in the terminal, if you
didn’t start android in the background (& parameter) then there’ll be no prompt, in this case
press Ctrl+Z to pause android then enter the command bg:
$ bg
This will allow android to run in
the background.
Install npm:
Node Packaged Modules
$ sudo apt-get install npm
Install Phonegap
$ sudo npm install -g phonegap
Install NodeJS
$ sudo apt-get install nodejs
Install ia32 libs
$ sudo apt-get install ia32-libs
Install adb
$ sudo apt-get install
android-tools-adb
Fool OS into thinking nodejs is node
There are two packages in the
Ubuntu repository that go by the name node, node is an amateur packet radio
program and nodejs is an event based server side JavaScript engine.
Unfortunately most nodejs programs will expect to use a binary called “node” so
we link that back to nodejs, thus:
$ sudo ln -s /usr/bin/nodejs
/usr/local/bin/node
As an aside, it’s probably better
to not try this development on a PC where the amateur packet radio program
“node” is installed or required since you may run into some compatibility
issues.
Install hardware virtualisation helpers.
Emulating an android device without
hardware virtualisation will be a slow and painful experience
$ sudo apt-get install qemu kvm
Create an AVD
Create an AVD (Android Virtual
Device) to test the apps on, to do this go back to the Android SDK Manager
(hopefully it will finish downloading/installing before you use it) go to Tools
-> Manage AVDs. Add a new one
- Click the [New…] button. Give it a name, e.g. “nexus”
- Select device (e.g. Nexus 7).
- Select target (API Level, your choice).
- Select CPU (Intel Atom will work best with hardware virtualisation, you can select ARM if you want but it will be slower, much slower)
- Select a skin, your preference.
- Optionally select camera(s). Mine crashed when I tried to use it but you may get lucky, you can select Emulated as the camera, it will work but the pictures won’t actually be real.
- Optionally change memory options from defaults, you will need to enter a number in the SD Card if you want to use the camera.
- Optionally tick [Use Host GPU], this may help the graphics redraw rate if you have a decently powered GPU, I’ve not really noticed a difference yet.
- Press OK to save.
Don’t start the AVD yet otherwise
it will start in emulation mode and be quite slow. If you don’t have a bin
directory in your home directory then create one, the next time bash starts, it
will add it to your path if it exists. Create a script file to start the AVD :
$ gedit ~/bin/nexus
Enter the following text:
#!/bin/sh
echo Starting Nexus…
emulator –avd nexus –qemu –enable-kvm &
echo Starting Nexus…
emulator –avd nexus –qemu –enable-kvm &
Save and exit gedit, make the file
executable:
$ chmod +x ~/bin/nexus
You can also get a bit more
elaborate and have that script start any AVD you want, e.g.
#!/bin/bash
if [ "$1" == "" ]; then
avd=nexus
echo No parameter specified, defaulting to $avd
if [ "$1" == "" ]; then
avd=nexus
echo No parameter specified, defaulting to $avd
else
avd=$1
fi
echo Starting android avd $avd
emulator -avd $avd -qemu -enable-kvm &
avd=$1
fi
echo Starting android avd $avd
emulator -avd $avd -qemu -enable-kvm &
This script will fail if you have
set the chosen AVD to have an ARM chip but you can also start the AVD from the
Android Virtual Device Manager, although bear in mind that when you do this,
the manager will not want to exit until the emulator is closed.
By now, you should have an Android
emulator up and running
With that, you should be good to
go, swipe to unlock the android device and create a phonegap app:
$ phonegap create myApp
$ cd myApp
$ phonegap run android
Addendum (28th Feb 2016):
With recent updates to phonegap, you may receive an error message saying it cannot find the module "bplist-parser", you can remedy this by installing it with the following command:
$ npm install -g bplist-parser
Monday, 16 December 2013
SQL Server Database Engine Tuning Advisor
I noticed a problem whilst doing some routine tuning. I had a query that I wanted to improve as the profiler told me it was doing a lot of work. I ran this through the Database Engine Tuning Advisor (DETA) but I guess I must have started it up wrong.
I was in another copy of the database when I was looking at this query (the two databases were identical in both structure and data). I then fired up DETA, which had selected "DatabaseB", I de-selected this and selected "DatabaseA" and ran the analysis.
The result came back, no improvement, no recommendations. I was surprised by this as I was expecting some index suggestions, I opened the view in design mode and examined the indices on the tables myself and saw what IMHO was quite a lack of at least 2 indices that I would have though would speed things up.
Curiously, I logged the Management Studio onto DatabaseA and ran it again, 2 indices suggested and 99% improvement estimated.
So it would seem that you should choose your database before firing up DETA or it would (I suspect) still run the query in the original database it was launched from but only examine tables from the selected database.
I was in another copy of the database when I was looking at this query (the two databases were identical in both structure and data). I then fired up DETA, which had selected "DatabaseB", I de-selected this and selected "DatabaseA" and ran the analysis.
The result came back, no improvement, no recommendations. I was surprised by this as I was expecting some index suggestions, I opened the view in design mode and examined the indices on the tables myself and saw what IMHO was quite a lack of at least 2 indices that I would have though would speed things up.
Curiously, I logged the Management Studio onto DatabaseA and ran it again, 2 indices suggested and 99% improvement estimated.
So it would seem that you should choose your database before firing up DETA or it would (I suspect) still run the query in the original database it was launched from but only examine tables from the selected database.
Monday, 17 December 2012
Warning about SQL Server Scheduled Tasks
I've had cause to create scheduled tasks on SQL Server in the past and in general it's a simple process, write a bit of T-SQL, test it, put it on a job and schedule it, not much can go wrong, right?
Well on occasion it does go wrong if you're logged into a SQL Server as 'domain_name\trevor.best' then that will be the name of the owner of the job, seems logical. What isn't logical is when you get an error stating that it cannot verify my user name when it's OK with me being logged in normally to create the job.
The workaround for this is to set the owner to a SQL Server user (e.g., sa).
The moral of the story is once you've set up a scheduled task, hang around to make sure it runs on schedule.
Well on occasion it does go wrong if you're logged into a SQL Server as 'domain_name\trevor.best' then that will be the name of the owner of the job, seems logical. What isn't logical is when you get an error stating that it cannot verify my user name when it's OK with me being logged in normally to create the job.
The workaround for this is to set the owner to a SQL Server user (e.g., sa).
The moral of the story is once you've set up a scheduled task, hang around to make sure it runs on schedule.
Monday, 10 December 2012
Assigning Variables in SQL Server (T-SQL)
I came across a problem today whereby a stored procedure didn't behave as expected. I suppose when I think about it, it behaved as it should have but my expectation was lacking the thought mentioned before.
There's two different ways of assigning a variable to a value stored in a table, one is to use a subquery in a "set" statement and the other is a simple select, e.g.
Set Statement
set @MyVar = (select field from table where otherfield=@othervar)
Select Statement
select @MyVar = field from table where otherfield=@othervar
Both ways will yield the same result as long as there is a result in the table, the difference is when there are no records in the table that you are selecting from. The first example will yield a null whereas the second won't assign a value to the variable at all. If the variable was null to start with then the result will look the same but if @MyVar held a value other than null before then it will still have that previous value.
Something to think about if assigning variables this way within a loop.
There's two different ways of assigning a variable to a value stored in a table, one is to use a subquery in a "set" statement and the other is a simple select, e.g.
Set Statement
set @MyVar = (select field from table where otherfield=@othervar)
Select Statement
select @MyVar = field from table where otherfield=@othervar
Both ways will yield the same result as long as there is a result in the table, the difference is when there are no records in the table that you are selecting from. The first example will yield a null whereas the second won't assign a value to the variable at all. If the variable was null to start with then the result will look the same but if @MyVar held a value other than null before then it will still have that previous value.
Something to think about if assigning variables this way within a loop.
Friday, 8 June 2012
SQL Server Management Studio Reconnecting
As I run several virtual machines, I usually save their state overnight when I shut my laptop down. If I'm running SQL Server Management Studio it will get disconnected as suspending a virtual machine will temporarily disconnect it from the network.
Upon restoring the VM, if I go to run a query in a window that's already open, I will get the following error.
This was quite frustrating as the "reconnect" button was greyed out so I thought it wise to reconnect to the server before running the query again. This presented two problems:
1) I don't always remember to reconnect
2) Reconnecting logged me onto the "master" database and the query might not work very well there or accidentally create an array of unnecessary objects in the wrong database.
I have since found though, that if you run the query and get the above error, simply running the query again will automatically reconnect you to the server and the correct database.
Upon restoring the VM, if I go to run a query in a window that's already open, I will get the following error.
Msg 10054, Level 20, State 0, Line 0
A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.)
A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.)
This was quite frustrating as the "reconnect" button was greyed out so I thought it wise to reconnect to the server before running the query again. This presented two problems:
1) I don't always remember to reconnect
2) Reconnecting logged me onto the "master" database and the query might not work very well there or accidentally create an array of unnecessary objects in the wrong database.
I have since found though, that if you run the query and get the above error, simply running the query again will automatically reconnect you to the server and the correct database.
Tuesday, 15 May 2012
Access newer Microsoft Access databases from VB6
I had to update a legacy program today that was written in VB6 and imports data from Access (jet) databases, the company that make the Access applications have upgraded to Access 2010 from the 2003 format that they were using so the import program immediately failed.
Luckily, Microsoft still support this scenario with the aid a new download http://www.microsoft.com/en-us/download/details.aspx?id=23734 that replaces the DAO library. Once installed, you can remove the reference to DAO 3.6 (or earlier) and add a reference to "Microsoft Office 12 access database engine object library". This new library appears to be backwards compatible with the old .MDB formats as well.
Luckily, Microsoft still support this scenario with the aid a new download http://www.microsoft.com/en-us/download/details.aspx?id=23734 that replaces the DAO library. Once installed, you can remove the reference to DAO 3.6 (or earlier) and add a reference to "Microsoft Office 12 access database engine object library". This new library appears to be backwards compatible with the old .MDB formats as well.
Monday, 14 May 2012
GNOME 3 on two monitors
I've been using the GNOME 3 desktop in Linux for a while now, since they made it available in Ubuntu 11.10 and I've now upgraded both my work and home machines to 12.04 LTS. Alas when I got to work, I plugged in my external monitor, ran the NVidia configuration and all was well until I switched to a new desktop and found the windows from the first desktop on the second monitor were still visible.
It appears the default behavior in GNOME 3 is only enable switching desktops on the primary monitor, anyway it didn't take a lot of googling especially as Greg Cordt's blog was the first result http://gregcor.com/2011/05/07/fix-dual-monitors-in-gnome-3-aka-my-workspaces-are-broken/ Thanks Greg.
It appears the default behavior in GNOME 3 is only enable switching desktops on the primary monitor, anyway it didn't take a lot of googling especially as Greg Cordt's blog was the first result http://gregcor.com/2011/05/07/fix-dual-monitors-in-gnome-3-aka-my-workspaces-are-broken/ Thanks Greg.
Thursday, 5 January 2012
Tortoise Right-Click Menu
Just a little one I found, on the right-click in Explorer you sometimes get a "SVN Get Lock" and sometimes you don't (If you don't then it's available in the Tortoise sub-menu anyway). I thought that this was a little inconsistent at first but since playing with the properties on the server I see that the menu option appears if the "svn:needs-lock" property is set for that file on the server.
BTW, setting the lock property of multiple files is rather difficult in Tortoise, well, not difficult, just laborious as it only allows you to do it one at a time. You can do it to a whole load by using a Linux machine, install SVN on it ("sudo apt-get install svn" for Ubuntu/Mint/Debian based distros) then you can use the command line:
The above sets it for all asp files, use a different spec for that, remember to commit your changes after though using the "svn commit" command.
BTW, setting the lock property of multiple files is rather difficult in Tortoise, well, not difficult, just laborious as it only allows you to do it one at a time. You can do it to a whole load by using a Linux machine, install SVN on it ("sudo apt-get install svn" for Ubuntu/Mint/Debian based distros) then you can use the command line:
$ svn propset svn:needs-lock 1 *.asp
The above sets it for all asp files, use a different spec for that, remember to commit your changes after though using the "svn commit" command.
Thursday, 22 December 2011
Insert into ADO (something) values (gotcha)
Yep, another gotcha. This time revolving around a SQL Identity column, when inserting a row into a table, you might want to know what SQL Server has populated the identity column with, in SQL this is done by using a built in function called "scope_identity()". I use this to get around another gotcha in that using the build in global variable "@@Identity" is flakey at best as if the table has a trigger that inserts into another table with an identity column then @@Identity will contain the value fro mthe other table.
Using VB6 and ADO to insert into a table, you can open a recordset on the following SQL:
set nocount on
insert into MyTable (GroupCode, TypeCode, Description, SomeID)
values ('TBTEST', 'Blah', 'UnitTest 39408.8', Null)
set nocount off
select scope_identity()
The one row and column that is returned is the value of scope_identity(), which is the value we want.
Now opening this recordset presents problems as unless you specify a forward-only cursor type, the ADO engine will read back and forth in the recordset, not normally a problem for normal recordsets, if a little wasteful (re-reading the recordset many times when you only asked it to read it once) but on this recordset that executes stuff as well it is a real problem.
If you open up the recordset, and it re-reads the first record, the insert statement is executed again, this would result in a duplicate record being inserted into the table or an error occurring if a unique index/constraint has been violated.
The simple solution is to use a forward-only cursor when opening the recordset, e.g.
rst.Open strSQL, Me.Connection, adOpenForwardOnly, adLockReadOnly
This will ensure that the insert statement at the begining of the SQL is only excuted the once.
Using VB6 and ADO to insert into a table, you can open a recordset on the following SQL:
set nocount on
insert into MyTable (GroupCode, TypeCode, Description, SomeID)
values ('TBTEST', 'Blah', 'UnitTest 39408.8', Null)
set nocount off
select scope_identity()
The one row and column that is returned is the value of scope_identity(), which is the value we want.
Now opening this recordset presents problems as unless you specify a forward-only cursor type, the ADO engine will read back and forth in the recordset, not normally a problem for normal recordsets, if a little wasteful (re-reading the recordset many times when you only asked it to read it once) but on this recordset that executes stuff as well it is a real problem.
If you open up the recordset, and it re-reads the first record, the insert statement is executed again, this would result in a duplicate record being inserted into the table or an error occurring if a unique index/constraint has been violated.
The simple solution is to use a forward-only cursor when opening the recordset, e.g.
rst.Open strSQL, Me.Connection, adOpenForwardOnly, adLockReadOnly
This will ensure that the insert statement at the begining of the SQL is only excuted the once.
Friday, 2 December 2011
A couple of VB6 gotchas
If, like me, you're lucky enough to be maintaining legacy software written in ancient development platforms then you're probably used to workarounds rather than waiting for a product to be fixed.
I came across a couple of particularly scary ones in the VB6 environment concerning the loading and saving of files, I say scary because what it actually loads and saves might not be what you'd expect.
Firstly the loading, once a project is loaded, it seems to have a mindset that it is the only program that could possibly be altering any files so that when you close and reload a module for instance, it doesn't actually read the code from the disk but appears to use a cached version of the file. This is great for speed but bad news if like me, you use third party programs that could alter the source files independent of the VB6 environment.
An example would be Tortoise SVN, where if you have different developers working on a project and you're not using an SCC plug-in then getting the latest version of a source file may be futile if the VB6 environment doesn't actually read it and uses its cached version instead, then you will be working with an out of date source file that after saving, will not incorporate the latest amendments from the others in your team.
Workaround: Short of always using a SCC plug-in, which given what's in the marketplace currently, I'd rather not, it'll be a case of closing VB6 down and re-opening it.
Secondly, on saving. In just about every other language or development platform that I have developed in, when you compile the application to an executable, it automatically saves all the source files that you are working on. VB6 is different, being more of a tokeniser than a real compiler, again it's using what it has cached in RAM to convert to an executable rather than in older 3GLs, a separate compiler program would have been called to parse the source file(s) and hence the need to save them automatically when you compile.
So now I have a DLL that is compiled and managed to check in a source file that doesn't, brilliant.
Workaround: Hit the save button.
The only problem with these workarounds is that you have to remember to do them.
I came across a couple of particularly scary ones in the VB6 environment concerning the loading and saving of files, I say scary because what it actually loads and saves might not be what you'd expect.
Firstly the loading, once a project is loaded, it seems to have a mindset that it is the only program that could possibly be altering any files so that when you close and reload a module for instance, it doesn't actually read the code from the disk but appears to use a cached version of the file. This is great for speed but bad news if like me, you use third party programs that could alter the source files independent of the VB6 environment.
An example would be Tortoise SVN, where if you have different developers working on a project and you're not using an SCC plug-in then getting the latest version of a source file may be futile if the VB6 environment doesn't actually read it and uses its cached version instead, then you will be working with an out of date source file that after saving, will not incorporate the latest amendments from the others in your team.
Workaround: Short of always using a SCC plug-in, which given what's in the marketplace currently, I'd rather not, it'll be a case of closing VB6 down and re-opening it.
Secondly, on saving. In just about every other language or development platform that I have developed in, when you compile the application to an executable, it automatically saves all the source files that you are working on. VB6 is different, being more of a tokeniser than a real compiler, again it's using what it has cached in RAM to convert to an executable rather than in older 3GLs, a separate compiler program would have been called to parse the source file(s) and hence the need to save them automatically when you compile.
So now I have a DLL that is compiled and managed to check in a source file that doesn't, brilliant.
Workaround: Hit the save button.
The only problem with these workarounds is that you have to remember to do them.
Tuesday, 22 November 2011
Single parent childless families
I was updating a DLL that takes XML from a web page and extracts the data from it to update a database. The web control had been upgraded from a simple data grid to a tree grid.
The DLL only handled data grids so I wrote a new routine to handle the whole tree grid, which would recursively process the child nodes.
In the original routine, I put a check for any tree like behavior within the XML and kick it out to the calling process with a simple message - "Tree", the calling process would see this message and call my new routine to process the XML in a different way.
Little did I realise that my check in the first routine had a slight bug in it, it kicked normal data grids back as trees as well but the whole process still worked, this is because the routine that handles trees with all the child nodes also handles straight lists as well.
A straight list is but a tree without the child nodes, so no problem then. I didn't leave it there of course, I tidied up the code and made it look like I meant to do that in the first place. :-)
The DLL only handled data grids so I wrote a new routine to handle the whole tree grid, which would recursively process the child nodes.
In the original routine, I put a check for any tree like behavior within the XML and kick it out to the calling process with a simple message - "Tree", the calling process would see this message and call my new routine to process the XML in a different way.
Little did I realise that my check in the first routine had a slight bug in it, it kicked normal data grids back as trees as well but the whole process still worked, this is because the routine that handles trees with all the child nodes also handles straight lists as well.
A straight list is but a tree without the child nodes, so no problem then. I didn't leave it there of course, I tidied up the code and made it look like I meant to do that in the first place. :-)
Tuesday, 8 November 2011
A Light hearted one
I was compressing a large file in 7Zip when I decided to cancel it, it prompted me to make sure.
So, I presume that [Yes] would cancel it, [No] would not and ahem, [Cancel], what do you do? Cancel the compression or Cancel the request to cancel?
So, I presume that [Yes] would cancel it, [No] would not and ahem, [Cancel], what do you do? Cancel the compression or Cancel the request to cancel?
Wednesday, 26 October 2011
Have you tried turning it off and on again?
Have you ever wondered why IT support people ask you to turn it off and on again?
Well, sometimes it is just to get you off their back whilst they finish off their morning coffee and croissant.
Sometimes it helps, like it as not, software has bugs and some of those bugs manifest themselves as memory leaks. A memory leak is where a program will allocate memory for its own use but not completely release it before allocating more memory later on, if left unchecked a program can consume vast amounts of memory and slow the system down and/or prevent other programs from executing properly. Other times it could be a program that gone into some infinite loop and hogs the CPU thereby denying CPU time to other processes.
You could try tracking down such problems but as support time is usually paid for by either the client or the software house providing the support, it is generally preferable to resolve an issue quickly rather than string it out for long periods of (costly) time.
Other times, turning it off and on again is the only way, e.g., consider your Internet connection, if it slowed down after a while you might call your ISP's support line, the first thing they usually tell you to do is turn your router off for 10 seconds and switch it back on again. This is because your connection is going down a telephone line that is logically split into pipes, each pipe can carry a certain amount of traffic and the pipe that you're connected to may be very busy, a simple disconnect and reconnect may cure the problem by the sheer fact that reconnecting will generally connect you to a less busy pipe.
Another thing you may ask, why do support guys ask you to power something off for 10 seconds before powering it back on? I'm no electronics expert but I would imagine this has something to do with allowing the capacitors to discharge fully as they can still retain charge some time after powering off, after all, they are in there to smooth out the current in the first place so removing the power for a very short period of time may not completely power down the unit hence the delay asked for by the support technician.
Well, sometimes it is just to get you off their back whilst they finish off their morning coffee and croissant.
Sometimes it helps, like it as not, software has bugs and some of those bugs manifest themselves as memory leaks. A memory leak is where a program will allocate memory for its own use but not completely release it before allocating more memory later on, if left unchecked a program can consume vast amounts of memory and slow the system down and/or prevent other programs from executing properly. Other times it could be a program that gone into some infinite loop and hogs the CPU thereby denying CPU time to other processes.
You could try tracking down such problems but as support time is usually paid for by either the client or the software house providing the support, it is generally preferable to resolve an issue quickly rather than string it out for long periods of (costly) time.
Other times, turning it off and on again is the only way, e.g., consider your Internet connection, if it slowed down after a while you might call your ISP's support line, the first thing they usually tell you to do is turn your router off for 10 seconds and switch it back on again. This is because your connection is going down a telephone line that is logically split into pipes, each pipe can carry a certain amount of traffic and the pipe that you're connected to may be very busy, a simple disconnect and reconnect may cure the problem by the sheer fact that reconnecting will generally connect you to a less busy pipe.
Another thing you may ask, why do support guys ask you to power something off for 10 seconds before powering it back on? I'm no electronics expert but I would imagine this has something to do with allowing the capacitors to discharge fully as they can still retain charge some time after powering off, after all, they are in there to smooth out the current in the first place so removing the power for a very short period of time may not completely power down the unit hence the delay asked for by the support technician.
Subscribe to:
Posts (Atom)


