Thursday, September 10, 2015

Adventures in Medication

As processes get more complex, there is a tendency to try automating and streamlining the process. Usually when something goes wrong in that automated chain, humans intervene, and whatever one-off issue is handled by some form of intelligence and life moves on.

Apparently this doesn't necessarily apply to healthcare. At least not in this case. And yet again I get confirmation bias that when insurers talk about the need for onerous copays so people take responsibility for their healthcare decisions, it's deflective and disingenuous. 

I had an appointment with my doctor. My blood sugars are still off, and she reiterated a need to lose weight and lower the blood sugars. But this time she said there's a drug that shows promise in lowering blood sugars without weight gain as a potential side effect. As a matter of fact, one of the side effects is weight loss. 

I'd asked her on a previous visit about the possibility of getting an appetite suppressant. At the time she offered a fat blocker. If you know what a fat blocker does, you can imagine the potential side effects for someone who has an hour commute through the subways and sidewalks of the city are not pleasant. So...no.

So this new medication, called Victoza, was good news to me. Oh, sure, there's some potentially (potentially) horrible side effects, but so does obesity and high blood sugar. She had her office call in the prescription on Monday.

A day later the prescription showed up in my pharmacy's system. But unlike the other prescriptions the office renewed, which were ready for pickup when I checked, the Victoza was showing up as "on hold" due to insurance issues. 

"I'll give it another day, they're probably having to get it authorized." Although I did notice that the Victoza was not called Victoza. It was called Saxenda.

I wasn't too worried, though. See, Saxenda and Victoza are just other names for Liraglutide. Medications are substituted all the time for equivalents, so I didn't think anything of it. 

That is, until I gave it a little more time and the hold was still on the medication. I complained about this on Twitter and my insurance company replied with a suggestion to email their "let us help you" line. I emailed them the details of what was happening.

Their rep looked into it and said our plan doesn't cover obesity medication.

"Uh...this was prescribed for diabetes," I said. I also made a half-snarky query regarding whether injectable insulin was covered. 

In the meantime I sent a message to the doctor's office relaying what the insurance company was saying. The response I get back is something about the issue being sent to some department that handles insurance claims or...interaction...something. They handed it off to a group whose job is dealing with insurance, I think.

So now I have the insurance company help people looking at the issue and I'm told the hospital is looking into it. 

The insurance people get back to me, telling me that insulin is covered under the plan. He also said that the Saxenda being using for diabetes treatment might be possible if the doctor tried submitting an authorization to use it for that purpose. "The information I have is indication(sic) Saxenda as an anti-obesity drug, which is not covered."

 I am finding it amusing at this point that they have no qualms about covering diabetes medication but treatments to try lowering weight is not covered, when I have little doubt that the cost of the side effects of obesity are probably more expensive by several factors. 

I then talked to our HR person who directed me to a contact with the third party benefits management company that acts as our liaison with the insurance company. After some back and forth, she said that "...what it comes down to is that Saxenda is not on their formulary list of covered medications. Every insurance carrier has a formulary and although one particular drug is covered another one in the same drug class may not be covered. When we pushed back to our rep to have this reviewed again she sent us an excerpt from the Saxenda website which states this is a weight loss drug, and it also states that it is not for the treatment of type 2 diabetes. This being said, Cigna does not cover weight loss medications so that is the reason they would not cover Saxenda under any circumstances."

This...was strange. They're going by website copy for the drug? 

Keep in mind that Saxenda is another name for Liraglutide. Liraglutide is another name for Victoza. Exact same drug...press releases for Saxenda don't hide this fact. See, the manufacturer of Victoza, Novo Nordisk, noticed that people taking Victoza were losing weight at a more-than-coincidental rate. So Novo took Victoza to the FDA and had the drug evaluated for weight loss under the marketing name Saxenda. Same drug. Different name. After trials, Saxenda was approved as a weight loss drug; the only difference I could find in any of the literature was the dosage.

So they're rejecting the drug because...it's showing as Saxenda?

It turns out Saxenda is listed as a "for fatties" drug while Victoza is listed as a "for diabetics" drug. Again, the only difference is the name.

But now I notice they are entirely focused on Saxenda. Not Victoza. I message the doctor's office and they verify that the prescription was in fact for Victoza. Also the doctor's office sent a prescription for Lantus since the insurance company continued to deny coverage.

Another side note; the messages from the third party management company and insurance company both expressed regret that I didn't get the news I hoped for. I assume that this is a polite way of appearing to care.

Shortly after that message I get another from the insurance company helpline explaining that he was working from the RX number I provided in my initial emails. 

Now I know that:
  1. The doctor wrote a prescription for Victoza
  2. The pharmacy is trying to authorize Saxenda
  3. The pharmacy is using an RX number that somehow maps to Saxenda when it's referenced
  4. Everyone involved is literally going by the prescription name Saxenda with no regard to what Saxenda is
  5. They believe the information literally given by the promotional website
I open the Victoza website and send the reps the following cut/paste:

What is Victoza®?
Victoza® is an injectable prescription medicine that may improve blood sugar (glucose) in adults with type 2 diabetes, and should be used along with diet and exercise.

I asked if this was covered under our drug plan, and the insurance company and third-party company both tell me that yes, Victoza is covered under our company health plan. My eyes couldn't possibly roll back any harder.

I asked the insurance company what RX number my doctor would have to use in order to get that particular medication prescribed. They reply that she can't; "The RX number can change depending on the manufacturer of medication and pharmacy you go to. Even a particular pharmacy may change their RX numbers from time to time. So you would not want to use the RX number to fill a prescription,  you would want to use the drug name specifically."

Now I know that while they can refer to the RX number and map it to a particular drug at that pharmacy, the numbers apparently aren't static. 

The third-party management company, when posed the same question, said: "It just has to be a Prescription for Victoza and they should not include DAW (dispense as written) so the pharmacy can fill it with the generic if there is one available."

I pass this information to the doctor's office...again...and they send in the prescription. This time it passes through their system without any problem.

It took me a week...actually closer to a week and a half...to get the prescription filled.

This adventure had a hospital, insurance company, a third party management company, and possibly the pharmacy all involved in sorting this mess out, and it appears no one but me knew (and the doctor) that Saxenda and Victoza were names for Liraglutide. A two minute Google search would have told them this, and yet it didn't occur to anyone to say, "Hey, the patient keeps talking about diabetes, and Saxenda with the name Victoza is the diabetes version of the drug! We can probably pass it through the system without any problems!"

I can't help but feel that I did the work that people in three companies over the course of a week and a half were supposed to do in less time.

This is why I have come to believe the whole "patient taking responsibility" thing is bullshit. There is no way the average person could be reasonably expected to know things like how RX numbers are mapped to drugs that may or may not be referenced (I would have thought they were a type of serial number...apparently it depends entirely on the pharmacy and manufacturer, and they can change without warning. Not. Useful.)

Even when I was trying to sort out what was going on, it was like the left hand didn't know what the right hand was doing. It didn't occur to anyone in this chain to figure out Liraglutide was the drug I was supposed to get? No one could work with the doctor to figure out what was needed? 

I invested a lot of time trying to get this sorted out. I'm not a medical professional. I don't know how all these different parts in the grand scheme of healthcare work. And yet these are the organizations that say the patient needs to take responsibility for healthcare decisions (read: make the cost cheaper for the insurance company). They were paying all these people to do something I ended up solving for free (except for my time that I'll never get back.)

Worse, as I tried not to slip into despair at how hopeless it felt to deal with these companies that all sounded like they wanted nothing to do with me after the indication that "we don't deal with fattie drugs, fattie," I can tell the typical patient would just give up. The doctor's office issued a new prescription for a different type of drug (Lantus is insulin, which tends to lead to weight gain...) and as far as I could tell that was the end. That is how I felt in dealing with the mechanisms of the system. The doctor's office and insurance companies routinely do this dance; who was I to fight the system? They're experienced in this matter, and an "oh well, try this drug and see if the insurance company okays it" approach is apparently par for the course.

There is simply no way for the patient to make reasonable decisions in healthcare without being an expert in how all the pieces work. The simple brushoff with...for lack of a better term...victim blaming is a disingenuous mask to hide a broken system and shove responsibility away from the real bad actors. I highly recommend people look into Steven Brill's Bitter Pill article, or his followup work, for more insight on how the healthcare system screws everyone over. 

Friday, September 4, 2015

Golang Web Application and MSSQL Injection Attacks

Not long ago I wrote a post on the first steps in developing an application that talks to an MSSQL database.

Those examples worked, obviously. I was compiling and testing the application before posting information. The example was my test case for a package that was later integrated into an application that integrated a web application with database access; that was when someone pointed out something that I should have checked earlier, but hadn't.

Namely in this line:

 // Add a record entry
 _, err := db.Exec("USE " + strDBName + "; INSERT INTO testtable (source, timestamp, content) VALUES ('" + strSource + "','" + strconv.FormatInt(int64Timestamp, 10) + "','" + strContent + "');")

In this statement there is a bit of content that comes from a user and is added to the database (namely strContent). Because it is concatenated, the string passed can be either a parameter or part of a query; a mischievous user could send commands to alter the database rather than just a value to add to the table.

Whoopsie!

I'll leave it up to you to Google what SQL injection attacks are. There has been a metaphorical ton of digital ink spilled discussing that topic. The summary is they're bad, and they're a very basic mistake in making a web app.

The good news in my case is that for what I was doing, the strContent string was partially filtered; before it was hitting the database, it was being fed into the template library. The template library made the text safe for HTML rendering, so much of the punctuation needed to turn that data into part of a query was transformed into HTML punctuation.

That's kind of a leather armor defense against injection attacks. The next step is to upgrade to chain mail.

The next thing to do is parameterize the query. This makes sure the query doesn't treat that string as part of the query to execute, parameterizing encapsulates the string and protects the database from clever users.

In Go, parameterization is characterized by:

db.Query("SELECT name FROM users WHERE age=?", userinput)  // OK
db.Query("SELECT name FROM users WHERE age=" + userinput)  // BAD

I altered the sample entry by doing the following:

 // Add a record entry
strTimeStamp := strconv.FormatInt(int64Timestamp, 10)
_, err := db.Exec("INSERT INTO "+strDBName+" (source, timestamp, content) VALUES (?,?,?);", strSource, strTimeStamp, strContent)

Basically the "?" marks are stand-ins for the variables in the query statement. I'm not sure if that fully secures the application from injection attacks, but I think it is a step in the right direction. If anyone has more information or suggestions, feel free to leave a comment...

Monday, August 31, 2015

Burger King: Have it Your Way, Unless It Take Effort

Burger King has long been known as the chief rival to McDonalds and home to one of the scariest and creepiest mascots in advertising history. But for me, the local Burger King is an amazing anomaly in lessons on running a business.

See, this business has managed to consistently deliver poor service over the years while still staying in business. It became a joke in my family that ordering from the local business was a game in Russian Roulette. Orders never seemed to come out right. There was a streak where I think I had 5 visits and, without fail, they failed to get the order correct. Once I went there and ordered just a soda.

One soda.

They gave me the wrong one.

Really? I ordered one lousy soft drink and you still screwed it up?

At this point most reasonable people would just say, "Don't go there anymore."

To them I say, "No shit?" Because that's what I did. If I was asked where to go for a fast food outing, the local BK was definitely on the bottom of that list. I told people I knew that I despised that place and it was a den of incompetence.

My son is still young enough to not care about such things. "Good enough" meant he had his cheeseburger or croissant sandwich. I'm not sure why he adores the food there. Perhaps part of it is not having to pay actual money to be inconvenienced by details such as, "Do I really want to get up and return this thing I didn't order and ask for my actual order?"

They've gotten better,...but at this point I don't really care.

Sin one: they rarely got my order right. Even simple ones. Like for a single drink.

The other day he was begging to go there for breakfast. It served as a source of more bafflement because I had their sausage, egg and cheese croissan'wich and the sausage tasted burned. Not just grilled...kind of charred on the surface of the patty. But at least it wasn't a piece of charcoal through and through. Edible, but the taste left something to be desired.

Sin two: the food prep doesn't seem very...consistent?

Many years ago...my wife says it was around 2007...my son was with his grandparents when he had an incident at this restaurant. This Burger King has their own play area, with slides and climby parts and...I don't know what else. But my son somehow had a matchbox car drop into a gap in the play area jungle-gym-ish climbing area.

He reached into the gap to retrieve the toy and the plastic pieces pinched together, entrapping him. I found out after everything was said and done and the fire department had left that my son was okay, just a little rattled. I don't think he ever went into the play area again. Yeah...the workers were clueless about what to do, and the fire department helped free him.

He managed to get stuck despite being supervised in a public restaurant playground area. And it was good he was being watched...I shudder to think of what happened if the play area had shifted just right that it could have crunched his arm.

There are certain risks to playing in a playground, and we accept that. But this was more of a maintenance issue. And it created a safety issue. I wanted to contact Burger King and let them know that maybe they might want to be careful about this...you know...inspect their playground equipment once in awhile.

Sin three: child-eating playground equipment.

Contacting Burger King was a challenge, to say the least. They had no Twitter account (Twitter launched in 2006, after all...); I could find no contact on their web page, there was no sign of an email address. The rest of the world had some form of electronic contact. Burger King gave customers an electronic middle finger.

Not kidding. A quick check on the Internet Archive at http://web.archive.org/web/20071006000851/http://burgerking.com/companyinfo/contactus.aspx (late 2007) came right out and said "E-mail communication is not accepted." In 2007. What the hell?

Sin four: about as tech savvy as a three year old, or perhaps K-Mart.

I did something that really just made me angry. I wrote them a letter. An actual, dead-tree, ink on paper letter. I mean, it was printed...I'm not a luddite and I know how to use a word processor. But it still irritated me that asking them (or their franchisees) to have some standard of not smooshing children in their playground equipment really shouldn't cost me money.

What I wanted was an acknowledgement that they'd do something to keep other kids from getting eaten by equipment. What I got was bupkis. I never heard back from Burger King. Not even some offhanded blame against their franchisee, pretending they have no control over how their image and name is represented. Nada. Zip.

My letter went into some great abyss of customer fuck-offs.

Sin five: at least have the decency to acknowledge something like this. There was a fire department called, you bastards.

What got me musing on the myriad reasons I avoid this BK when at all possible is my son's recent insistence...begging, really...that his special day out include a trip to Burger King for morning breakfast. I opened a web browser and it connected to my employer's website. I noticed that there was an oddly shaded and content-empty bar along the bottom of my web page.

Viewing the source showed some issues with loading something from an advertisement link. Which was strange, since my employer doesn't shove any weirdball ads like this at their users (I think it was blanked out because of an ad-block extension active in my browser at the time, rendering whatever their ad bar was supposed to be, blank, instead.)

I opened a new browser tab and navigated to my employer again, but this time used the https: link. That time the advertiser disappeared. See, using an encrypted point-to-point connection makes it difficult to inject extra HTML into my browsing session without me knowing...

...which meant Burger King, the company that for so many years makes it hard to actually contact them with any feedback and displayed a stunning lack of customer interaction and tech savviness, was injecting unwanted ads (and probably monitoring) my web browsing over their wifi.

Sin six: You're monitoring and injecting content into my browsing? Really?

I'm assuming that there was something about this buried in the legalese agreed upon when clicking to use their wifi, although to be honest, I don't remember clicking on anything in order to get on their wifi. And when it comes to public wifi, there's always the danger of your session being hijacked if you're not using a VPN or some other form of encryption. But still...another reason to dislike you?

I'm not sure how you stay in business other than being convenient for people in an area that doesn't have a lot of income. You're close to a retirement home, and getting to the Dunkin' Donuts would mean crossing the street in an area that has horrible crosswalk support. Maybe the Walmart model is at play; cheap food is cheap, so who cares about customer experience?

I even made a passive aggressive complaint on Twitter about their monitoring of web traffic and injecting code into the session (believe it or not, BK is on Twitter now...they joined in 2010. Yeah...little late to the party.) They said nothing. I've made irritated remarks about Dell and Time Warner and had them reply to me without even trying to talk to them. BK doesn't give a damn.

Sin seven: you monitor customer web traffic but not your mentions in Twitter. Get with the program.

Last I went to their website to contact them about the web-jacking. I clicked on the contact us page. It redirects to a "tellusaboutus.com" website.

They outsourced the "contact us."

A totally outside company handles "contact us" for Burger King.

Sin eight: ...I...no. That's enough.

Many companies are at least trying to not suck. They show signs of understanding how to engage with customers. They monitor for signs that customers want to communicate with them, want help, want feedback, want acknowledgement (hey, hear of Netflix? Or Dominoes? Or any of the dozens of other companies that will get in the news with some playful banter on Twitter with customers?)

Most companies at a minimum make it easy to email them with complaints or suggestions. Hell, I've had companies that pester me for feedback via email.

Burger King is like a digital brick wall. They seem to actively not want customer feedback.

...I suppose that kind of explains quite a bit.

I'll look forward to what the next five years holds for Burger King. If McD's is feeling the financial pinch, it may not be long before Burger King topples over. Can't say I'll miss them.

Tuesday, August 25, 2015

Haiku OS...Noticed Something a Little Strange

I was updating my Haiku VM and noticed something a little strange in Top. I checked some Ps output and...yup. It's there too.


Do you see the weirdness?

If not, I'll try making it more obvious.



The "Big Brother" one was the first thing that caught my eye. Was something infecting Haiku?

Who would bother targeting an operating system with a sliver of market share? An OS still in development, for that matter? Perhaps a pissed developer?

These thoughts were going through my head as I weighed the decision to shut down the VM in case it was doing something to probe the network.

I did a quick check online for more information about this...surely someone else had noticed weird processes like that. I found that someone had indeed noticed and asked about this awhile ago; they were pointed to the AppManager.cpp source in Github.


So..."Big Brother" is a humorous way of naming a watchdog process. What about the ancient movie reference? I found a chat transcript from someone else who was rather puzzled as well:



So they're...intentional?

I understand geek humor being integrated with different projects. I'm hardly surprised when I hear there's some little easter egg hidden in the source code, or when there's a somewhat obvious integration of technology with a geeky cultural icon (like OS/2 having a release named Warp.)

I'm not quite so sure about the wisdom of having something with ominous connotations being used as a thread name in a process list, especially in the age of Edward Snowden. And there's something about having a reference to Austin Powers that just...doesn't fit at all into the project. It's not in a theme. It's not...anything. An inside joke? Is it trying to date the project in some way?

At best these are quirks that make you pause and wonder if someone drank too much before making a commit. At worst doing things like this adds to a perception that the project isn't really meant to be taken seriously. At least, in my opinion.

I'm all for fun jokes and geeky humor. I love the little hidden easter eggs in out of the way places. I'm just not sure about humor that pops out in a nonsensical manner like a hernia bulge with no rhyme or reason, hinting that it's up to something nefarious.

Sunday, August 23, 2015

Upgrading Raspberry Pi From Golang 1.4x to 1.5

Some additional notes with my adventures working on an older ARM-based Pi computer and Go. Basically this is notes...not a how-to, but handy reference, so it will probably be a bit more terse than my usually over-narrative writing style.

First I logged in to the Pi and ran screen, because I'm remote on a free wifi connection 150 miles from the Pi and I know it's a hijacked connection from Burger King so trusting its reliability is iffy at best.

Second, I couldn't get the "git checkout go1.5" command to work. So I took my existing ~/go directory and moved it to another directory. Go is now self-bootstrapped...it likes the previous build being available. And it looked for a specific subdirectory. So...

mv ./go ./go1.4
git clone https://go.googlesource.com/go
cd go
git checkout go1.5
cd src
./all.bash

From there it went through the build process, compiling Go with Go (nifty, huh?)


Friday, August 21, 2015

GoLang and MSSQL Databases: An Example

(I'll insert the sources for custom_DB_functions.go and sqltest.go at the end of the post.)
(Addendum - I recently ran into an issue with the query of the database in the custom_DB_functions.go package where calls returned an invalid object. It looks like you have to call it with the schema as well [mydatabase.myschema.mytable] to get the call to work. See this StackOverflow question for details.)

I created a small utility recently that pulled data from a text file to display on a web page. I showed it to my manager, and he said we might be able to integrate it with a more useful bit of our infrastructure already in place, but in order to do that, it would have to talk to an MSSQL server for content instead of the text file.

I'd never really worked with testing that setup. In searching the Internet for examples, there are lots of fragments providing hints how to do it...but nothing really spelled out an example in tutorial form. So I kept notes and now I'm sharing what I learned for other beginners that want to experiment with integrating an MSSQL database with their Go application.

I'm only going to hit some highlights in the source; the source code has quite a bit of commenting and is pretty self-documented (but if you have questions...or suggestions/corrections...please leave a comment! In the blog comments, that is.)

Creating a Test Database Server

 I wanted to set up an accessible test environment for anyone, not just people who happen to have a full-on SQL Server available. I fired up my Windows VM and downloaded MS SQL Server Express 2014. Free for most purposes!

I ran the installer (the 64 bit version with tools) keeping the defaults.

I had to enable network access to the database engine.

  • Open the SQL Server 2014 Configuration Manager
  • Click SQL Server Network Configuration in the left hand column
  • Open Protocols for SQLEXPRESS
    • Make sure TCP/IP is "enabled"
    • Right click TCP/IP, click Properties
    • Click the IP Addresses tab
    • Check that IP2 is in the local subnet
    • Check that TCP Dynamic Ports is blank in the IPALL section
    • Check that the TCP Port is set to 1433
  • Restart the SQL Server (SQLEXPRESS) service
At this point a quick NMap scan of the VM showed that port 1433 was open (when I used the -Pn flag.)

There's another setting to change coming up...

Prepare Your Go Project to Talk to The SQL Server

Go projects talking to a SQL server need two components; a driver, and a library that abstracts that driver from the programmer. The driver depends on what type of server you're talking to, but the abstraction layer is pretty standard.

Since we're talking to MSSQL, we'll use the go-mssqldb driver. From your Go workspace run:

go get github.com/denisenkom/go-mssqldb

I decided I was going to create a test application that imported a custom package of functions that specifically accessed the database; that way I could import the resulting package to my existing application and make necessary alterations at that point.

In the package I imported the driver with the line

_ "github.com/denisenkom/go-mssqldb"

WHAT IS THAT UNDERSCORE?

The problem is that I don't use the package identifier for anything in the program; when I tried to compile it, the compiler will error. What I really needed from the driver was the initialization method; the underscore will run the init() function but ignore everything else, and the compiler won't complain.

The abstraction part...the generic SQL Go functions to interact with the database...are imported with 

"database/sql"

That import is in my package (custom_DB_functions.go and sqltest.go.) The driver is only imported in the package.

The test program was literally a "add functions as I go along and verify they work" thing. Add a function, code it in the package, recompile...repeat until I had most of the functions I wanted to work. 

In order to make the test program flexible, I imported the flag package and created entries for connecting to the database from the command line. Import with

import (
     "flag"
)

In main(), I added a series of flags using 


// Flags
ptrVersion := flag.Bool("version", false, "Display program version")
ptrDeleteIt := flag.Bool("deletedb", false, "Delete the database")
ptrServer := flag.String("server", "localhost", "Server to connect to")
ptrUser := flag.String("username", "testuser", "Username for authenticating to database; if you use a backslash, it must be escaped or in quotes")
ptrPass := flag.String("password", "", "Password for database connection")
ptrDBName := flag.String("dbname", "test_db", "Database name")

flag.Parse()

You can probably divine the meaning from the syntax, but these are in the form of

<variable> := flag.<type>("flagname", default setting if not provided at command line, "Help explanation")

The variable created is a pointer, and flag.Parse() evaluates the flags at runtime. The default values are set to the second argument if they're not changed at the command line, so you can use them as variables without having to set them to something before referring to them.

The first function I wanted to test was the creation of a database handle. It seems that the behavior of Open relies on the underlying driver; it may, as the docs say, validate arguments without a connection to the database, so it may be necessary to actually do something with the handle before active connections are made. At any rate, here's the function in sqltest.go:

db, err := sql.Open("mssql", "server="+*ptrServer+";user id="+*ptrUser+";password="+*ptrPass)
if err != nil {
fmt.Println("From Open() attempt: " + err.Error())
}
 defer db.Close()

Now db is a handle to the database. Because of the way database connections are handled, you don't want to keep opening and closing them. Just defer the Close() until the program exits and that way you won't get goofy pooling/caching issues.

From what I can tell of the documentation the db handle must be kept open for the length of time that you're using it (don't close it until the program exits.) This lets the driver manage a pool of connections; when you operate on the database you use a connection from the pool. Those connection(s) you'll want to close so the connection gets returned to the connection pool. In this program I deferred the close of the db handle because the scope of the test program should keep it open until sqltest ends.

Basically Open() needs the type of database (MSSQL), the server IP or DNS name, the username, and password. I should also note that the username, if you're using Windows auth, the backslash must be entered twice so it's escaped properly or the username must be encased in quotes. for example, the connection at the command line might look like:

./sqltest -password=HelloThere -server=192.168.254.222 -username=MySystem\\testuser

Notice there's two backslashes in the username?

Skipping ahead a little, sqltest.go makes a call to PingServer(). In the package, PingServer looks like:

func PingServer(db *sql.DB) string {

err := db.Ping()
if err != nil {
return ("From Ping() Attempt: " + err.Error())
}

return ("Database Ping Worked...")

}

It's a rather simple function, and all it does is run a call to db.Ping and returns a string with an error or an affirmation that it's working. This created a working connection to the database (as discussed before), and also tested the ability to pass the database handle to a package function.

Something else to note in sqltest.go is that I called the initial Open() using sql.Open(), while the call to PingServer was simply PingServer(). The trick to that is in the import statement. 

import (
"database/sql"
"flag"
"fmt"
"os"
. "custom_DB_functions"
"strconv"
)

The import for "custom_DB_functions" is preceded by a period. That allows me to refer to the functions without the preceding library name; if I preceded "fmt" with a period I should be able to use lines like Println("I'm printing this to the console!") instead of fmt.Println("I'm printing this to the console!"). I don't know what happens if I had multiple functions with the same name in different packages imported with the period...I would think the compiler would insist on the proper namespace for referencing those specific cases, but I haven't tested it.

Skipping ahead a little more there's a spot where I create the database if it doesn't already exist:

// If it doesn't exist, let's create the base database
if !boolDBExist {

CreateDBAndTable(db, *ptrDBName)
fmt.Println("********************************")

}

In the library, the call looks like this:

func CreateDBAndTable(db *sql.DB, strDBName string) error {

// Create the database
_, err := db.Exec("CREATE DATABASE [" + strDBName + "]")
if err != nil {
return (err)
}

// Let's turn off AutoClose
_, err = db.Exec("ALTER DATABASE [" + strDBName + "] SET AUTO_CLOSE OFF;")
if err != nil {
return (err)
}

// Create the tables
_, err = db.Exec("USE " + strDBName + "; CREATE TABLE testtable (source nvarchar(100) NOT NULL, timestamp bigint NOT NULL, content nvarchar(4000) NOT NULL)")
if err != nil {
return (err)
}

return nil

}

It was here that I encountered an error from the database. 

Next Database Configuration Change: "CREATE DATABASE permission denied in database 'master'"

The actual SQL calls aren't all that difficult if you already understand SQL (the big notes involve not constantly opening and closing the database handle, and to use Query() when getting information back to process and Exec() when the reply is more or less either "this worked" or "error!" 

In the above calls, you can see that the function creates a database, alters the AUTO_CLOSE setting on the database so it doesn't throw goofball errors when trying later queries, and then creates a table with particular attributes. 

What I got back the first time was the CREATE DATABASE permission denied in database 'master' error. That required some more tinkering with the database engine.
  • Open SQL Server 2014 Management Studio and connect to the test database
    • Click on your SQL EXPRESS instance
    • Expand the Security folder
    • Expand the Logins folder
    • I created a local user on my system for testing, so I right clicked on BUILTIN\Users and select Properties
    • Click on "Server Roles" on the left side
    • Select "dbcreator" from the list of roles; this should be enough access
Clicking okay and re-running the database/table creation calls should work. CreateDBAndTable() and DropDB() were created mostly for testing purposes so I could periodically work with a fresh database without having to futz with Management Studio or other interface (and of course I learned how to do these tasks programmatically.)

Any Other Notes?

Between heavy commenting and naming functions and variables in a (hopefully) mostly obvious manner I think that the code is semi-obvious; most of what I would explain in text here would seem redundant or obvious. If you have questions feel free to leave a blog comment!

The only thing that comes to mind from the design point of view is the use of returning an error from the library functions instead of dumping something to the console. This means the caller is responsible for the presentation of messages; the application can decide if the returned message goes to the console or redirected to a file or possibly ignored.

Here's the source code! Hope it is somewhat helpful to someone! (Probably it will be most useful to me as a reference while trying to tune what I've been working on...)

Source Code

custom_DB_functions.go 

// Package custom_DB_functions contains functions customized to manipulate MSSQL databases/tables
// for our application
//
// Version 0.15, 8-13-2015
package custom_DB_functions

import (
 "database/sql"
 _ "github.com/denisenkom/go-mssqldb"
 "strconv"
)

// PingServer uses a passed database handle to check if the database server works
func PingServer(db *sql.DB) string {

 err := db.Ping()
 if err != nil {
  return ("From Ping() Attempt: " + err.Error())
 }

 return ("Database Ping Worked...")

}

// CheckDB checks if the database "strDBName" exists on the MSSQL database engine.
func CheckDB(db *sql.DB, strDBName string) (bool, error) {

 // Does the database exist?
 result, err := db.Query("SELECT db_id('" + strDBName + "')")
 defer result.Close()
 if err != nil {
  return false, err
 }

 for result.Next() {
  var s sql.NullString
  err := result.Scan(&s)
  if err != nil {
   return false, err
  }

  // Check result
  if s.Valid {
   return true, nil
  } else {
   return false, nil
  }
 }

 // This return() should never be hit...
 return false, err
}

// CreateDBAndTable creates a new content database on the SQL Server along with
// the necessary tables. Keep in mind the user credentials that opened the database
// connection with sql.Open must have at least dbcreator rights to the database. The
// table (testtable) will have columns source (nvarchar), timestamp (bigint), and
// content (nvarchar).
func CreateDBAndTable(db *sql.DB, strDBName string) error {

 // Create the database
 _, err := db.Exec("CREATE DATABASE [" + strDBName + "]")
 if err != nil {
  return (err)
 }

 // Let's turn off AutoClose
 _, err = db.Exec("ALTER DATABASE [" + strDBName + "] SET AUTO_CLOSE OFF;")
 if err != nil {
  return (err)
 }

 // Create the tables
 _, err = db.Exec("USE " + strDBName + "; CREATE TABLE testtable (source nvarchar(100) NOT NULL, timestamp bigint NOT NULL, content nvarchar(4000) NOT NULL)")
 if err != nil {
  return (err)
 }

 return nil

}

// DropDB deletes the database strDBName.
func DropDB(db *sql.DB, strDBName string) error {

 // Drop the database
 _, err := db.Exec("DROP DATABASE [" + strDBName + "]")

 if err != nil {
  return err
 }

 return nil

}

// AddToContent adds new content to the database.
func AddToContent(db *sql.DB, strDBName string, strSource string, int64Timestamp int64, strContent string) error {

 // Add a record entry
 _, err := db.Exec("USE " + strDBName + "; INSERT INTO testtable (source, timestamp, content) VALUES ('" + strSource + "','" + strconv.FormatInt(int64Timestamp, 10) + "','" + strContent + "');")
 if err != nil {
  return err
 }

 return nil

}

// RemoveFromContentBySource removes a record from the database with source strSource. The
// int64 returned is a message indicating the number of rows affected.
func RemoveFromContentBySource(db *sql.DB, strSource string) (int64, error) {

 // Remove entries containing the source...
 result, err := db.Exec("DELETE FROM testtable WHERE source=$1;", strSource)
 if err != nil {
  return 0, err
 }

 // What was the result?
 rowsAffected, _ := result.RowsAffected()
 return rowsAffected, nil

}

// Query the content in the database and return the source (string), timestamp (int64), and
// content (string) as slices
func GetContent(db *sql.DB) ([]string, []int64, []string, error) {

 var slcstrContent []string
 var slcint64Timestamp []int64
 var slcstrSource []string

 // Run the query
 rows, err := db.Query("SELECT source, timestamp, content FROM testtable")
 if err != nil {
  return slcstrSource, slcint64Timestamp, slcstrContent, err
 }
 defer rows.Close()

 for rows.Next() {

  // Holding variables for the content in the columns
  var source, content string
  var timestamp int64

  // Get the results of the query
  err := rows.Scan(&source, &timestamp, &content)
  if err != nil {
   return slcstrSource, slcint64Timestamp, slcstrContent, err
  }

  // Append them into the slices that will eventually be returned to the caller
  slcstrSource = append(slcstrSource, source)
  slcstrContent = append(slcstrContent, content)
  slcint64Timestamp = append(slcint64Timestamp, timestamp)
 }

 return slcstrSource, slcint64Timestamp, slcstrContent, nil

}
sqltest.go 
package main

// Notice in the import list there's one package prefaced by a ".",
// which allows referencing functions in that package without naming the library in
// the call (if using . "fmt", I can call Println as Println, not fmt.Println)
import (
 "database/sql"
 "flag"
 "fmt"
 "os"
 . "custom_DB_functions"
 "strconv"
)

const strVERSION string = "0.18 compiled on 8/11/2015"

// sqltest is a small application for demonstrating/testing/learning about SQL database connectivity from Go
func main() {

 // Flags
 ptrVersion := flag.Bool("version", false, "Display program version")
 ptrDeleteIt := flag.Bool("deletedb", false, "Delete the database")
 ptrServer := flag.String("server", "localhost", "Server to connect to")
 ptrUser := flag.String("username", "testuser", "Username for authenticating to database; if you use a backslash, it must be escaped or in quotes")
 ptrPass := flag.String("password", "", "Password for database connection")
 ptrDBName := flag.String("dbname", "test_db", "Database name")

 flag.Parse()

 // Does the user just want the version of the application?
 if *ptrVersion == true {
  fmt.Println("Version " + strVERSION)
  os.Exit(0)
 }

 // Open connection to the database server; this doesn't verify anything until you
 // perform an operation (such as a ping).
 db, err := sql.Open("mssql", "server="+*ptrServer+";user id="+*ptrUser+";password="+*ptrPass)
 if err != nil {
  fmt.Println("From Open() attempt: " + err.Error())
 }

 // When main() is done, this should close the connections
 defer db.Close()

 // Does the user want to delete the database?
 if *ptrDeleteIt == true {
  boolDBExist, err := CheckDB(db, *ptrDBName)
  if err != nil {
   fmt.Println("Error running CheckDB: " + err.Error())
   os.Exit(1)
  }
  if boolDBExist {
   fmt.Println("(sqltest) Deleting database " + *ptrDBName + "...")
   DropDB(db, *ptrDBName)
   os.Exit(0)
  } else {

   // Database doesn't seem to exist...
   fmt.Println("(sqltest) Database " + *ptrDBName + " doesn't appear to exist...")
   os.Exit(1)

  }
 }

 // Let's start the tests...
 fmt.Println("********************************")

 // Is the database running?
 strResult := PingServer(db)
 fmt.Println("(sqltest) Ping of Server Result Was: " + strResult)

 fmt.Println("********************************")

 // Does the database exist?
 boolDBExist, err := CheckDB(db, *ptrDBName)
 if err != nil {
  fmt.Println("(sqltest) Error running CheckDB: " + err.Error())
  os.Exit(1)
 }

 fmt.Println("(sqltest) Database Existence Check: " + strconv.FormatBool(boolDBExist))

 fmt.Println("********************************")

 // If it doesn't exist, let's create the base database
 if !boolDBExist {

  CreateDBAndTable(db, *ptrDBName)
  fmt.Println("********************************")

 }

 // Enter a test record
 boolDBExist, err = CheckDB(db, *ptrDBName)
 if err != nil {
  fmt.Println("(sqltest) CheckDB() error: " + err.Error())
  os.Exit(1)
 }

 if boolDBExist == true {

  err := AddToContent(db, *ptrDBName, "Bob", 1437506592, "Hello!")
  if err != nil {
   fmt.Println("(sqltest) Error adding line to content: " + err.Error())
   os.Exit(1)
  }

  err = AddToContent(db, *ptrDBName, "user", 1437506648, "Now testing memory")
  if err != nil {
   fmt.Println("(sqltest) Error adding line to content: " + err.Error())
   os.Exit(1)
  }

  err = AddToContent(db, *ptrDBName, "user", 1437503394, "test, text!")
  if err != nil {
   fmt.Println("(sqltest) Error adding line to content: " + err.Error())
   os.Exit(1)
  }

  err = AddToContent(db, *ptrDBName, "Bob", 1437506592, "Hope this works!")
  if err != nil {
   fmt.Println("(sqltest) Error adding line to content: " + err.Error())
   os.Exit(1)
  }

 }

 fmt.Println("(sqltest) Completed entering test records.")

 fmt.Println("********************************")

 fmt.Println("(sqltest) Deleting records from a particular source.")

 // Delete from a source
 int64Deleted, err := RemoveFromContentBySource(db, "user")
 if err != nil {
  fmt.Println("(sqltest) Error deleting records by source: " + err.Error())
  os.Exit(1)
 } else {

  // How many records were removed?
  fmt.Println("Removed " + strconv.FormatInt(int64Deleted, 10) + " records")
  fmt.Println("********************************")

 }

 // Get the content
 slcstrSource, slcint64Timestamp, slcstrContent, err := GetContent(db)
 if err != nil {
  fmt.Println("(sqltest) Error getting content: " + err.Error())
 }

 // Now read the contents
 for i := range slcstrContent {

  fmt.Println("Entry " + strconv.Itoa(i) + ": " + strconv.FormatInt(slcint64Timestamp[i], 10) + ", from " + slcstrSource[i] + ": " + slcstrContent[i])

 }

}