Gorm: Go test errors with mssql

Created on 13 Mar 2016  路  23Comments  路  Source: go-gorm/gorm

When using transactions the following error appears
mssql: The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.

Edit: Let's solve mssql errors one at a time

Most helpful comment

Hi @all, Fixed all tests for mssql 馃憦

All 23 comments

Hi @kiwih

Could you try to test on your local and point out how to fix the issue? as I can't test it out ;(

I am updating this issue to be the core source of mssql issues until we resolve them. I will perform whichever tests you would like.

Running go test as it stands (after removing the non-compiling TestCompatabilityMode function) is as follows:

testing mssql...
[info] replacing callback `create` from D:/GoDev/src/github.com/jinzhu/gorm/callback_system_test.go:94
[info] removing callback `create` from D:/GoDev/src/github.com/jinzhu/gorm/callback_system_test.go:107

鈫怺35m(mssql: IDENTITY_INSERT is already ON for table 'rogue.dbo.posts'. Cannot perform SET operation for table 'categories'.)鈫怺0m
鈫怺33m[2016-03-14 14:40:59]鈫怺0m 鈫怺31;1m 鈫怺0m

鈫怺35m(mssql: IDENTITY_INSERT is already ON for table 'rogue.dbo.posts'. Cannot perform SET operation for table 'categories'.)鈫怺0m
鈫怺33m[2016-03-14 14:40:59]鈫怺0m 鈫怺31;1m 鈫怺0m

鈫怺35m(mssql: Explicit value must be specified for identity column in table 'posts' either when IDENTITY_INSERT is set to ON or when a replication user is inserting into a NOT FOR REPLICATION identity
column.)鈫怺0m
鈫怺33m[2016-03-14 14:40:59]鈫怺0m 鈫怺31;1m 鈫怺0m
--- FAIL: TestBelongsTo (0.01s)
        association_test.go:21: Got errors when save post mssql: Explicit value must be specified for identity column in table 'posts' either when IDENTITY_INSERT is set to ON or when a replication us
er is inserting into a NOT FOR REPLICATION identity column.
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
        panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x40 pc=0x55a610]

goroutine 207 [running]:
testing.tRunner.func1(0xc08267f8c0)
        c:/go/src/testing/testing.go:450 +0x178
github.com/jinzhu/gorm.(*Scope).related(0x0, 0x869fc0, 0xc0825085f0, 0xc082584290, 0x1, 0x1, 0x0)
        D:/GoDev/src/github.com/jinzhu/gorm/scope.go:947 +0x40
github.com/jinzhu/gorm.(*Association).Find(0xc0825b2270, 0x869fc0, 0xc0825085f0, 0xc0825b2270)
        D:/GoDev/src/github.com/jinzhu/gorm/association.go:19 +0xc8
github.com/jinzhu/gorm_test.TestBelongsTo(0xc08267f8c0)
        D:/GoDev/src/github.com/jinzhu/gorm/association_test.go:34 +0x3d2
testing.tRunner(0xc08267f8c0, 0xcbb5f0)
        c:/go/src/testing/testing.go:456 +0x9f
created by testing.RunTests
        c:/go/src/testing/testing.go:561 +0x874

goroutine 1 [chan receive]:
testing.RunTests(0xa6c060, 0xcbb560, 0x7f, 0x7f, 0x869d01)
        c:/go/src/testing/testing.go:562 +0x8b4
testing.(*M).Run(0xc082571ef8, 0x86a3e0)
        c:/go/src/testing/testing.go:494 +0x77
main.main()
        github.com/jinzhu/gorm/_test/_testmain.go:312 +0x11d

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
        c:/go/src/runtime/asm_amd64.s:1696 +0x1

goroutine 11 [chan receive]:
database/sql.(*DB).connectionOpener(0xc0824f2960)
        c:/go/src/database/sql/sql.go:634 +0x4c
created by database/sql.Open
        c:/go/src/database/sql/sql.go:481 +0x33d
exit status 2
FAIL    github.com/jinzhu/gorm  0.467s

I believe that SET IDENTITY_INSERT ON must only be done when you are in fact inserting a record with a known identity. Otherwise, it must be left off

Hi @kiwih

Are you using github.com/jinzhu/gorm/dialects/mssql? I think it is only set IDENTITY_INSERT ON for inserting

Hi @jinzhu,

I'm using your main_test.go file, and the import is indeed present.

Cheers

I am experiencing this. If I attempt an insertion without explicitly specifying the fields constituting the PK, I get an error. So what is the appropriate logic here? I feel that if we do explicitly specify all PK fields on creation, we should be setting IDENTITY_INSERT ON, and if no PK fields are set, this should be turned off.

For example, the current implementation is as follows:

func setIdentityInsert(scope *gorm.Scope) {
    if scope.Dialect().GetName() == "mssql" {
        scope.NewDB().Exec(fmt.Sprintf("SET IDENTITY_INSERT %v ON", scope.TableName()))
    }
}

And I believe this would accomplish what I stated above.

func setIdentityInsert(scope *gorm.Scope) {
    if scope.Dialect().GetName() == "mssql" {
        //determine if identity insert must be on
        for _, b := range scope.PrimaryFields() {
        if b.IsBlank == false {
            scope.NewDB().Exec(fmt.Sprintf("SET IDENTITY_INSERT %v ON", scope.TableName()))
            return
        }
    }

    //turn off by default
    scope.NewDB().Exec(fmt.Sprintf("SET IDENTITY_INSERT %v OFF", scope.TableName()))
    }
}

I am also observing this when inserting into a MS SQL database. The change provided by @jordanchapian seemed to fix the issue for me.

Also, #941 may be a duplicate of this.

@devint1 My proposal above is not entirely correct. If IDENTITY_INSERT is set to on for table x, and you attempt to turn IDENTITY_INSERT on for table y, mssql will throw an error like IDENTITY_INSERT is already ON for table x

When I encountered this, I split setIdentityInsert(scope *gorm.Scope) into an intro and outro callback to ensure that IDENTITY_INSERT is turned off after the transaction.

I have a fork with these changes.

Any updates on getting these changes merged into the mssql driver?

Why would IDENTITY_INSERT be enabled at all by default? Most common use-case is probably to let the database itself handle primary keys. Or am I wrong?

EDIT: I've looked into this a bit more, the issue comes from issue #841, the problem here is IDENTITY_INSERT should ONLY be enabled when you manually want to set a value in an auto incrementing identity, the default here should be OFF. Gorm should not provide its own IDs by default, that's just asking for race conditions. Enabling this by default with every transaction effectively breaks transactions.

It's also broken, IDENTITY_INSERT can only be enabled for one table at a time, and there is no place that sets it to OFF again.

IDENTITY_INSERT should have to be a choice by the developer, and never forced.

I think the setIdentityInsert method should simply be removed, it's used in the wrong way, and it's broken in its current implementation since there's no provided way, other than a raw SQL query, to disable it again.

EDIT 2: While the fix by @jordanchapian would work, it still executes an extra query for every query in the transaction, extremely ineffective.

@jinzhu, have these changes been merged? I am also finding this issue, even when following the basic tutorial here: http://jinzhu.me/gorm/crud.html#create

By the way, SQL Server is now available on Linux and Docker which means you don't need windows to test them :)

@LuisBosquez I've opened a PR to remove the automatic IDENTITY_INSERT entirely, #1379, no progress or comments on that though.

Easiest fix at the moment is to just manually apply the changes in that PR, and vendor Gorm.

@LuisBosquez thank you for let me know the docker thing, let me test it!

@jinzhu this is the official Docker image mssql-server-linux I am one of the owners of the project. Currently working on a set of tutorials for SQL Server with GoLang in our new SQL Server tutorials website So please let me know if you plan to integrate this fix anytime soon :)

Hi @LuisBosquez

I have tried to setup test environment with the docker, but can't login database gorm with account gorm (able to login with sa), anything I missed?

CREATE LOGIN gorm WITH PASSWORD = 'LoremIpsum86' ;
CREATE DATABASE gorm;
sp_addrole 'gorm' , 'db_owner';

@jinzhu I tried to repro your issue, but it worked for me. Did you 'USE master' when you created the account? What's the error message you're seeing?

@LuisBosquez

Maybe this could help you finger out the issue easily

image

Here is my searched solution, but not sure how to do that in a linux docker http://www.sherweb.com/blog/the-server-principal-a-is-not-able-to-access-the-database-b-under-the-current-security-context-microsoft-sql-server-error-916/

@jinzhu Funny, I hadn't encountered that error before. What's the command you're using to run the docker image? The website mentions that this issue is related to setting up a different collation. Are you using one? How did you set it up?

I am using docker kitematic https://github.com/docker/kitematic started docker image (microsoft/mssql-server-linux), and only set environment ACCEPT_EULA, SA_PASSWORD, haven't setup any other things

@jinzhu I found the error. You are missing a step after creating the login and the database. You need to create a USER for the "gorm" database. The steps should be as it follows:

under "sa":

CREATE LOGIN gorm WITH PASSWORD = 'LoremIpsum86' ;
CREATE DATABASE gorm;
USE gorm;
CREATE USER gorm FROM LOGIN gorm -- links the user "gorm" to the login within the database.
sp_addrole 'gorm' , 'db_owner';

after that you can now run: mssql -s localhost -u gorm -p LoremIpsum86

and then:

USE gorm

Let me know if it works for you!

@LuisBosquez thank you, it works!

a little problem in your code is the last line should be:

`sp_changedbowner 'gorm';

but not

sp_addrole 'gorm' , 'db_owner';

Hi @all, Fixed all tests for mssql 馃憦

Hello I am having issues with MSSQL Server.

I tried to run an update statement and it failed.

tx := db.Begin()
    var m model.Menu
    if err := tx.Where("LOWER(code) = LOWER(?)", menu.Code).Find(&m).Error; err != nil && err == gorm.ErrRecordNotFound {
        fmt.Println("menu with code", menu.Code, "does not exist")
        handleError(tx, tx.Create(&menu))
    } else {
        m.Position = menu.Position
        m.Component = menu.Component
        m.Title = menu.Title
        m.Code = menu.Code
        handleError(tx, tx.Where("id = ?", m.ID).Find(&model.Menu{}).Updates(&m))
        menu = m
    }
    tx.Commit()

The issue it complained of is cannot update identity column 'id'
Please what is the recommended solution to updating in gorm when using MSSQL Server?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

izouxv picture izouxv  路  3Comments

littletwolee picture littletwolee  路  3Comments

alanyuen picture alanyuen  路  3Comments

satb picture satb  路  3Comments

bramp picture bramp  路  3Comments