Using the database/sql package in go for things like sql.Exec will return dynamically generated, unreferenced errors such as
"Error 1062: Duplicate entry '192' for key 'id'"
The problem is that it can also return errors such as
"Error 1146: Table 'tbl' doesn't exist"
From the same call to sql.Exec
How can I tell the difference between these two errors without
String comparison, or
Pattern matching for error code
Or are those idiomatic viable solutions for this problem?
database/sql package does not solve this problem. It's driver specific. For example, for mysql you can use:
if mysqlError, ok := err.(*mysql.MySQLError); ok {
if mysqlError.Number == 1146 {
//handling
}
}
Also, you can find some error constant package, like mysqlerr from VividCortex, and use it:
if mysqlError, ok := err.(*mysql.MySQLError); ok {
if mysqlError.Number == mysqlerr.ER_NO_SUCH_TABLE {
//handling
}
}
It's not much better than pattern matching, but seems to be more idiomatic.
I think there's no idiomatic solution, but I wrote a simple function for getting the error number, so you can easily compare them.
In this solution I assume that the construction of the error message is always the same: "Error -some number here-: Error description".
If there's no number in the error or something went wrong it returns 0.
func ErrorCode(e error) int {
err := e.Error() //the description of the error
if len(err) < 6 { //if its too small return 0
return 0
}
i := 6 //Skip the part "Error "
for ; len(err) > i && unicode.IsDigit(rune(err[i])); i++ {
} // Raising i until we reach the end of err or we reach the end of error code
n, e := strconv.Atoi(string(err[6:i])) //convert it to int
if e != nil {
return 0 //something went wrong
}
return n //return the error code
}
Go playground link: http://play.golang.org/p/xqhVycsuyI
Related
I'm trying to use go on a raspberry pi to query bluetooth low energy devices. It's functional, I can connect to the device I want and iterate through the services and characteristics of the connected device. Now I'm just trying to streamline things and just read/write the values I'm interested in. It isn't working.
Code:
func onPeriphConnected(p gatt.Peripheral, err error) {
fmt.Println("Connected")
defer p.Device().CancelConnection(p)
if err := p.SetMTU(500); err != nil {
fmt.Printf("Failed to set MTU, err: %s\n", err)
}
batteryServiceId := gatt.MustParseUUID("180f")
// Direct read attempt (not working)
batterySerivce := gatt.NewService(batteryServiceId)
batteryLevelUUID := gatt.MustParseUUID("2a19")
batteryChar := gatt.NewCharacteristic(batteryLevelUUID,batterySerivce,gatt.Property(0x12),0,0)
e, err := p.ReadCharacteristic(batteryChar)
if err != nil {
fmt.Printf("Failed to read battery level, err: %s\n", err)
} else {
fmt.Println(e)
}
// iterate services read (working)
ss, err := p.DiscoverServices(nil)
if err != nil {
fmt.Printf("Failed to discover services, err: %s\n", err)
return
}
for _, s := range ss {
if(s.UUID().Equal(batteryServiceId)) {
fmt.Println("Found the battery service")
// Discovery characteristics
cs, err := p.DiscoverCharacteristics(nil, s)
if err != nil {
fmt.Printf("Failed to discover characteristics, err: %s\n", err)
continue
}
for _, c := range cs {
msg := " Characteristic " + c.UUID().String()
if len(c.Name()) > 0 {
msg += " (" + c.Name() + ")"
}
msg += "\n properties " + c.Properties().String()
fmt.Println(msg)
if (c.Properties() & gatt.CharRead) != 0 {
b, err := p.ReadCharacteristic(c)
if err != nil {
fmt.Printf("Failed to read characteristic, err: %s\n", err)
continue
}
fmt.Printf(" value %x\n", b)
}
}
}
}
}
Results:
Connected
[10 0 0 1]
Found the battery service
Characteristic 2a19 (Battery Level)
properties read notify
value 53
You can see where I expect to get a hex value of 53 I'm instead getting an array of [10 0 0 1]. I'm pretty new to go so I'm probably missing something here or just assembling my read incorrectly. Any pointers are much appreciated. Thanks!
A link to the appropriate documentation would be advisable. I don't know if this link is correct as there seem to be multiple different versions of package gatt.
Edit: see also https://godoc.org/github.com/paypal/gatt/examples/service#NewBatteryService at https://github.com/paypal/gatt/blob/master/examples/service/battery.go, which appears to show the right way of creating a battery service directly. Original answer below.
Having had a quick scan through said documentation, two things leap out at me:
The battery level ID is 2a19. The battery service ID is 180f. You use:
batteryServiceId := gatt.MustParseUUID("180f")
batterySerivce := gatt.NewService(batteryServiceId)
batteryChar := gatt.NewCharacteristic(batteryLevelUUID, batterySerivce,
gatt.Property(0x12), 0, 0)
e, err := p.ReadCharacteristic(batteryChar)
(I kept variable name spellings, but added a bit of white space to fit better on the StackOverflow display.) You never call NewDescriptor nor either of AddDescriptor or SetDescriptors on batteryChar. Are such calls required? I don't know; the documentation doesn't say. But the call that works uses DiscoverServices followed by DiscoverCharacteristics, which perhaps does create these (documented but undescribed) Descriptors. They look like they interpose themselves in value-oriented operations, so they might be critical.
Looking further at the code, after or instead of creating a characteristic directly, I think you do have to at least link the characteristic back into the service. The right call might be AddCharacteristic or SetCharacteristics. See this chunk of code in DiscoverCharacteristics.
(Minor.) gatt.Property(0x12) is definitely the wrong way to construct the constant. You probably should use:
gatt.Property.CharRead | gatt.Property.CharNotify
I am trying to read Redis Key-val in Go. Key is string and value is JSON string. Eg- Key=
discov_32161296
and Value as Json string=
"{\"10283\":true,\"11064\":true,\"15123\":true,\"15447\":true,\"15926\":true,\"16530\":true,\"16537\":true,\"16799\":true,\"17088\":true,\"17249\":true,\"18501\":true,\"18529\":true,\"18601\":true,\"3044\":true,\"3687\":true,\"4926\":true,\"5483\":true,\"6\":true,\"6675\":true,\"8332\":true,\"8336\":true,\"8674\":true}"
Getting below error while reading in Go
redis.Values err redigo: unexpected type for Values, got type []uint8
Here's my code :
uIDDiscoveryOffer := fmt.Sprintf("%s_%d", "discov", uid)
opDataStr, err := redis.String(redis.Values(con.Do("GET", uIDDiscoveryOffer)))
if err != nil || err != redis.ErrNil {
utils.Log1("readCacheTxnByUID-Disc-redis.Values-err", fmt.Sprint("redis.Values err : ", uidDiscoveryOffer, " error: ", err.Error()))
} else {
//Some Logic
}
The Redis GET returns the value of a key. redis.Values() may be used to convert the result of a command that returns multiple items.
Since GET returns a single item, only use redis.String(), you don't need redis.Values() here:
opDataStr, err := redis.String(con.Do("GET", uIDDiscoveryOffer))
I'm trying to understand golang interface, my problem is that why err2.What undefined.
Here is a simple code. The output indicates that both err and err2 have same type as *main.MyError, but err2 have no field "What", so there must be some difference between err and err2, but I cannot figure out the difference here. I just began learning golang not long before, any help will be greatly appreciated.
package main
import (
"fmt"
"time"
"reflect"
)
type MyError struct {
When time.Time
What string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v, %s",
e.When, e.What)
}
func run() error {
return &MyError{
time.Now(),
"it didn't work",
}
}
func main() {
err := &MyError{time.Now(), "Hello"}
fmt.Println(reflect.TypeOf(err))
fmt.Println(err.What)
err2 := run()
fmt.Println(reflect.TypeOf(err2))
fmt.Println(err2.What)
}
expected output:
main.MyError
Hello
main.MyError
it didn't work
actual output:
\# command-line-arguments
./test.go:34:18: err2.What undefined (type error has no field or method What)
The function run() returns a value of type error, which is an interface type. Yes, it wraps a value of concrete type *MyError, but to get access to MyError's fields, you need to use a type assertion:
fmt.Println(err2.(*MyError).What)
Try it on the Go Playground.
Note that a value of error type may contain values of other concrete types, actually any that implements the error interface. If it would contain a value of another type, the above type assertion would result in a runtime panic.
If you're unsure err2 actually holds a value of type *MyError and you want to avoid the runtime panic, you may use the special form of type assertion to get this information and only act if it is so:
if myerror, ok := err2.(*MyError); ok {
fmt.Println(myerror.What) // Here myerror has static type *MyError
} else {
fmt.Println("Some other error:", err2)
}
Try this one on the Go Playground.
I think the interface of error type is let you use Error() method without any detail in the concrete structure. You can check on the Go Playground
Hi everyone,
I am trying to test C programs that use an user input... Like a learning app. So the avaliator(teacher) can write tests and I compile the code with a help of a docker and get back the result of the program that I send. After that I verify if one of the case tests fails..
for that I have two strings, like this:
result = "input_compiled1540323505983: /home/compiler/input/input.c:9: main: Assertion `B==2' failed. timeout: the monitored command dumped core Aborted "
and an array with case tests that is like:
caseTests = [" assert(A==3); // A must have the value of 3;", " assert(B==2); // B must have the value of 2; ", " assert(strcmp(Fulano, "Fulano")==0); //Fulano must be equal to Fulano]
I need to send back from my server something like this:
{ console: [true, true, true ] }
Where each true is the corresponding test for every test in the array of tests
So, I need to test if one string contains the part of another string... and for now I did like this:
criandoConsole = function(arrayErros, arrayResult){
var consol = arrayErros.map( function( elem ) {
var local = elem.match(/\((.*)\)/);
if(arrayResult.indexOf(local) > -1 ) {
return false;
}
else return true;
});
return consol;
}
I am wondering if there are any more efective way of doing that. I am using a nodejs as server. Does anyone know a better way?!
ps: Just do like result.contains(caseTests[0]) did not work..
I know this is changing the problem, but can you simplify the error array to only include the search terms? For example,
result = "input_compiled1540323505983: /home/compiler/input/input.c:9: main: Assertion `B==2' failed. timeout: the monitored command dumped core Aborted ";
//simplify the search patterns
caseTests = [
"A==3",
"B==2",
"strcmp(Fulano, \"Fulano\")==0"
]
criandoConsole = function(arrayErros, arrayResult){
var consol = arrayErros.map( function( elem ) {
if (arrayResult.indexOf(elem) != -1)
return false; //assert failed?
else
return true; //success?
});
return consol;
}
console.log(criandoConsole(caseTests,result));
I am writing a package using Rcpp Function, the package compiles, and R CMD Check also works fine. Earlier, the input to package's cvode function was an XPtr, but now the input can be both XPtr or an R or Rcpp function (the implementation was based on a earlier post). Currently, input functions in R, Rcpp and Rcpp::XPtr work in the package.
The package had previously had clang-UBSAN issues, so I am trying to detect them beforehand now using rhub package. On running check_with_sanitizers() command from the rhub package, I am getting the following error:
eval.c:677:21: runtime error: member access within null pointer of type 'struct SEXPREC'
─ *** caught segfault ***
address (nil), cause 'memory not mapped'
Segmentation fault (core dumped)
I have been able to isolate the error to the line ydot1 = rhs_fun(t, y1); in the following piece of code, i.e., commenting/un-commenting the expression above reproduces the error.
My question is - is there a check I should be performing before calling the rhs_fun Function, to avoid the segmentation fault error?
Note - check_with_valgrind() produces no error.
Thanks!
// struct to use if R or Rcpp function is input as RHS function
struct rhs_func{
Function rhs_eqn;
};
int rhs_func(realtype t, N_Vector y, N_Vector ydot, void* user_data){
// convert y to NumericVector y1
int y_len = NV_LENGTH_S(y);
NumericVector y1(y_len); // filled with zeros
realtype *y_ptr = N_VGetArrayPointer(y);
for (int i = 0; i < y_len; i++){
y1[i] = y_ptr[i];
}
// convert ydot to NumericVector ydot1
// int ydot_len = NV_LENGTH_S(ydot);
NumericVector ydot1(y_len); // filled with zeros
// // cast void pointer to pointer to struct and assign rhs to a Function
struct rhs_func *my_rhs_fun = (struct rhs_func*)user_data;
if(my_rhs_fun){
Function rhs_fun = (*my_rhs_fun).rhs_eqn;
// use the function to calculate value of RHS ----
// Uncommenting the line below gives runtime error
// ydot1 = rhs_fun(t, y1);
}
else {
stop("Something went wrong, stopping!");
}
// convert NumericVector ydot1 to N_Vector ydot
realtype *ydot_ptr = N_VGetArrayPointer(ydot);
for (int i = 0; i< y_len; i++){
ydot_ptr[i] = ydot1[i];
}
// everything went smoothly
return(0);
}
An update - based on the comments below, I have added checks. So the check succeeds, but I can see the rhs_fun is NULL as the code goes to the stop message.
if(my_rhs_fun){
Function rhs_fun = (*my_rhs_fun).rhs_eqn;
// use the function to calculate value of RHS ----
if (rhs_fun){
ydot1 = rhs_fun(t, y1);
}
else{
stop("Something went wrong");
}
}
else {
stop("Something went wrong, stopping!");
}
An added check is added to the struct also
if (Rf_isNull(input_function)){
stop("Something is wrong with input function, stopping!");
}
The checks succeed, but I see that rhs_fun is NULL as the else message is printed
Error in cvode(time_vec, IC, ODE_R, reltol, abstol) :
Something went wrong
Execution halted
Not sure why, as the examples I have tried have worked without complaints.
The most likely candidate for a NULL reference is rhs_fun. So it makes sense to test that before executing the function:
if(rhs_fun) {
...
} else {
stop(...)
}
The R API function Rf_isNull would not be appropriate here, since that checks for an SEXP of type NILSXP and segfaults for an actual nullptr.
In addition I would check that you are not inserting a NULL reference into the struct, though I find it unlikely that anything is going wrong there.
Overall this is just a workaround. It would be interesting to know what triggers this behavior.