@@ -3,15 +3,16 @@ package insert
33import (
44 "context"
55 "fmt"
6+ "reflect"
7+ "sync"
8+
69 "github.com/viant/sqlx"
710 "github.com/viant/sqlx/io"
811 "github.com/viant/sqlx/metadata"
912 "github.com/viant/sqlx/metadata/info"
1013 "github.com/viant/sqlx/metadata/info/dialect"
1114 "github.com/viant/sqlx/metadata/sink"
1215 "github.com/viant/sqlx/option"
13- "reflect"
14- "sync"
1516)
1617
1718type numericSequencer struct {
@@ -68,7 +69,7 @@ func (n *numericSequencer) nextSequence(ctx context.Context, sess *session, reco
6869 return nil , nil
6970 case dialect .PresetIDStrategyUndefined :
7071 n .shallPresetIdentities = false
71- n .updateSequence (ctx , n .getSequenceName (sess ), recordCount )
72+ n .updateSequencer (ctx , n .getSequenceName (sess ), recordCount )
7273 return nil , nil
7374 case dialect .PresetIDWithMax :
7475 options = append (options , n .maxIDSQLBuilder (sess ))
@@ -89,32 +90,26 @@ func (n *numericSequencer) nextSequence(ctx context.Context, sess *session, reco
8990 return n .sequence , nil
9091}
9192
92- func (n * numericSequencer ) transientDMLBuilder (sess * session , record interface {}, batchRecordBuffer []interface {}, recordCount int64 ) func (* sink.Sequence ) (* sqlx.SQL , error ) {
93- return func (sequence * sink.Sequence ) (* sqlx.SQL , error ) {
93+ func (n * numericSequencer ) transientDMLBuilder (sess * session , record interface {}, batchRecordBuffer []interface {}, recordCount int64 ) func (* sink.Sequence ) (* sqlx.SQL , int64 , error ) {
94+ return func (sequence * sink.Sequence ) (* sqlx.SQL , int64 , error ) {
9495 resetAutoincrementQuery := sess .Builder .Build (record , option .BatchSize (1 ))
9596 resetAutoincrementQuery = sess .Dialect .EnsurePlaceholders (resetAutoincrementQuery )
9697 sess .binder (record , batchRecordBuffer , 0 , len (sess .columns ))
9798
9899 values := make ([]interface {}, len (sess .columns ))
99100 copy (values , batchRecordBuffer [0 :len (sess .columns )- 1 ]) // don't copy ID pointer (last position in slice)
100101
101- oldValue := sequence .Value
102- var passedValue int64
103-
104- switch recordCount {
105- default :
106- sequence .Value = sequence .NextValue (recordCount )
107- if diff := sequence .Value - oldValue ; diff < recordCount {
108- return nil , fmt .Errorf ("new next value for sequenceName %d is too small, expected >= %d but had " , sequence .Value , oldValue + recordCount )
109- }
110- passedValue = sequence .Value - sequence .IncrementBy // decreasing is required for transient insert approach
102+ maxIdValue , err := sequence .ComputeNextForTransient (recordCount )
103+ if err != nil {
104+ return nil , 0 , err
111105 }
112- values [len (sess .columns )- 1 ] = & passedValue
106+
107+ values [len (sess .columns )- 1 ] = & maxIdValue
113108 resetAutoincrementSQL := & sqlx.SQL {
114109 Query : resetAutoincrementQuery ,
115110 Args : values ,
116111 }
117- return resetAutoincrementSQL , nil
112+ return resetAutoincrementSQL , recordCount , nil
118113 }
119114}
120115
@@ -149,50 +144,41 @@ func (n *numericSequencer) getColumn() io.Column {
149144}
150145
151146func (n * numericSequencer ) prepareSequenceIfNeeded (ctx context.Context , sess * session , record interface {}, columnValue * interface {}, recordCount int , identitiesBatched []interface {}, options []option.Option ) error {
152- // presetting sequence only once reserves (if implemented) sequence values on db only one time
153- if n .detectedPreset {
154- return nil
155- }
156-
157- if recordCount == 0 {
147+ // presetting sequence only once reserves (if implemented) sequence values on db only one time per batch operation
148+ if recordCount <= 0 {
158149 return nil
159150 }
160151
161152 n .muxPreset .Lock ()
153+ defer n .muxPreset .Unlock ()
154+
162155 if n .detectedPreset {
163- n .muxPreset .Unlock ()
164156 return nil
165157 }
166158
159+ if columnValue == nil {
160+ return fmt .Errorf ("columnValue is nil" )
161+ }
162+
167163 isColumnZeroValue := isZero (* columnValue )
168164 n .shallPresetIdentities = isColumnZeroValue
169165
170166 if isColumnZeroValue {
171- var err error
172- n .sequence , err = n .nextSequence (ctx , sess , record , identitiesBatched , recordCount , options )
167+ seq , err := n .nextSequence (ctx , sess , record , identitiesBatched , recordCount , options )
173168 if err != nil {
174- n .muxPreset .Unlock ()
175169 return err
176170 }
177- //} else { // n.sequence should be nil (it's not in use), and it's important in afterFlush func
178- // n.updateSequence(ctx, n.getSequenceName(sess), recordCount)
171+ n .sequence = seq
179172 }
180173
181174 if n .sequence != nil && n .shallPresetIdentities && n .sequenceValue == nil {
182- var seqValue int64
183-
184- switch recordCount {
185- case 1 : // TODO not proved that miss some edge cases, if does then only default case should be used
186- seqValue = n .sequence .Value - n .sequence .IncrementBy
187- default :
188- seqValue = n .sequence .MinValue (int64 (recordCount ))
189- }
190-
175+ seqValue := n .sequence .MinValue (int64 (recordCount ))
191176 n .sequenceValue = & seqValue
192177 }
193178
194- n .detectedPreset = true // detectPreset must be here to avoid sending 0 in preset mode to db
195- n .muxPreset .Unlock ()
179+ // detectPreset must be set at the end to avoid sending 0 in preset mode to db
180+ n .detectedPreset = true
181+
196182 return nil
197183}
198184
@@ -237,7 +223,7 @@ func (n *numericSequencer) afterFlush(ctx context.Context, values []interface{},
237223 }
238224 //in case there is a batch insert, we need to check if last inserted ID is the same as the sequence value
239225 //if so we can safely update the identities with the new sequence value within the batch
240- n .updateSequence (ctx , n .sequence .Name , int (rowsAffected ))
226+ n .updateSequencer (ctx , n .sequence .Name , int (rowsAffected ))
241227 sequenceValue = n .sequence .Value
242228 expectedNextInsertID := (1 + rowsAffected ) * inceremntBy
243229 if expectedNextInsertID != sequenceValue { //race condition during batch insert, skip updating IDs
@@ -272,7 +258,7 @@ func isZero(value interface{}) bool {
272258 }
273259}
274260
275- func (n * numericSequencer ) updateSequence (ctx context.Context , sequenceName string , recordCount int ) {
261+ func (n * numericSequencer ) updateSequencer (ctx context.Context , sequenceName string , recordCount int ) {
276262 meta := metadata .New ()
277263 options := []option.Option {option .NewArgs (n .session .info .Catalog , n .session .info .Schema , sequenceName ), n .session .Dialect }
278264
0 commit comments