Problems getting program arguments

Hello, I’m continuing my investigations into "Big Data’ and with this in mind have started to experiment with the denisenkom/go-mssqldb Golang package. Because I’m getting connection problems, I thought I would try debugging. So I set up my launch.json like this:

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch",
      "type": "go",
      "request": "launch",
      "mode": "debug",
      "remotePath": "",
      "port": 2345,
      "host": "127.0.0.1",
      "program": "${fileDirname}",
      "env": {},
      "args": ["-server 192.168.99.100 -user sa -password <MyPassword> -port 1433"],
      "showLog": true
    }
  ]
}

I’m running SQL Server in a Docker container, but I know by connecting with MS SQL Operations Studio that 192.168.99.100 is the correct server address.

I’m trying to run the example code from the denisenkom/go-mssqldb package which is as follows:

package main

import (
	"database/sql"
	"flag"
	"fmt"
	"log"

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

var (
	debug    = flag.Bool("debug", false, "enable debugging")
	password = flag.String("password", "", "the database password")
	port     = flag.Int("port", 1433, "the database port")
	server   = flag.String("server", "", "the database server")
	user     = flag.String("user", "", "the database user")
)

func main() {

	flag.Parse()

	if *debug {
		fmt.Printf(" password:%s\n", *password)
		fmt.Printf(" port:%d\n", *port)
		fmt.Printf(" server:%s\n", *server)
		fmt.Printf(" user:%s\n", *user)
	}

	connString := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d", *server, *user, *password, *port)
	if *debug {
		fmt.Printf(" connString:%s\n", connString)
	}
	conn, err := sql.Open("mssql", connString)
	if err != nil {
		log.Fatal("Open connection failed:", err.Error())
	}
	defer conn.Close()

	stmt, err := conn.Prepare("select 1, 'abc'")
	if err != nil {
		log.Fatal("Prepare failed:", err.Error())
	}
	defer stmt.Close()

	row := stmt.QueryRow()
	var somenumber int64
	var somechars string
	err = row.Scan(&somenumber, &somechars)
	if err != nil {
		log.Fatal("Scan failed:", err.Error())
	}
	fmt.Printf("somenumber:%d\n", somenumber)
	fmt.Printf("somechars:%s\n", somechars)

	fmt.Printf("bye\n")
}

The problem seems to occur when the flag.Parse() line is hit. The error message is flag provided but not defined: -server 192.168.99.100 -user sa -password <MyPassword> -port 1433. A quick look on StackOverflow tells me:

flag.Parse() is being called before your flag is defined.
You have to make sure that all flag definitions happen before calling flag.Parse(), usually by defining all flags inside init() functions.

But I thought that the lines in the var block:

var (
    	debug    = flag.Bool("debug", false, "enable debugging")
    	password = flag.String("password", "", "the database password")
    	port     = flag.Int("port", 1433, "the database port")
    	server   = flag.String("server", "", "the database server")
    	user     = flag.String("user", "", "the database user")
    )

constituted the necessary flag definition. Indeed the standard documentation has example code following the same pattern. What am I missing?

This gives your program one argument consisting of the entire string above. This is the flag that is then considered underfined. You probably want something like

"args": ["-server", "192.168.99.100", "-user", ... and so on

Windows argument parsing is finicky and I’m not really sure what reads the launch.json, but that is at least how it’s supposed to work.

I wondered about this. The format I used was based on a StackOverflow answer that had been upvoted and generally praised to the hilt. I should learn not to trust so much!

I’ll try splitting up the code, as you suggest. Thanks, Jakob!

This is getting strange. The code no longer falls over at flag.Parse() but instead, the code carries on but the flag variables are not being set, apart from port which is taking the specified default value of 1433. I suspect the formatting of the launch.json probably needs more tweaking. By the way, Jakob, you mentioned “Windows” argument parsing. Does the fact that I’m doing this on VSCode for the Apple Mac make any difference?

Hmmm. This comment https://github.com/Microsoft/vscode/issues/2167#issuecomment-173864770 would suggest that Jakob’s answer is correct, but, try as I might, I cannot get those variables to show up. For the purposes of this program I could, of course, just hard-code the parameters in, but since command line parameters are such a common occurrence, I feel that I should, at least, attempt to master them! I’ve tried using - and -- for the parameters but my understanding is that Golang isn’t so fussy about that, ironically enough!

Compile and run it manually to see what happens.

I assumed Windows because you mentioned MS SQL, the post started with a large Microsoft comment block, and you didn’t specify. :slight_smile:

I did some experimenting with the manual command line and I have it running! The answer was to specify the command line as go run simple.go -debug=true -server=192.168.99.100 -user=sa -password=<MyPassword> -port=1433 (Note the = signs).

With this in mind, I then tweaked the args sections of the launch.json file to:

  "args": [
    "-debug=true",
    "-server=192.168.99.100",
    "-user=sa",
    "-password=<MyPassword>",
    "-port=1433"
  ],

And, whaddya know, it runs perfectly!

It’s strange that I must have read at least 10 articles which all gave me information, supposedly verified by others, but which, seemingly turned out to be incorrect. I suppose these periods of utter bewilderment followed by the euphoric relief of the resolution of a problem is what drives us to do this crazy coding thing…

@calmh Sorry about not mentioning the Apple Mac thing. I switched from 30 years of MS Windows use and I freely admit, I have become a little complacent and find it difficult to accept that anyone could choose to use anything but a Mac. It’s an old machine by today’s standards but it does have 32Gb of RAM on board (my old Win box had 4Gb) so it doesn’t hang around. And pretty much any coding job I want to do is perfectly possible, especially now that MS has released VSCode. I’m running SQL Server on Docker Toolbox which is really easy to manage as well so happy days!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.