github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/databases/dboperation.go (about) 1 // Copyright 2023 IAC. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package dbconn 16 17 import ( 18 "context" 19 "database/sql" 20 "fmt" 21 "strings" 22 "time" 23 24 "github.com/mdaxf/iac/com" 25 "github.com/mdaxf/iac/engine/types" 26 "github.com/mdaxf/iac/logger" 27 28 _ "github.com/denisenkom/go-mssqldb" 29 _ "github.com/go-sql-driver/mysql" 30 ) 31 32 type DBOperation struct { 33 DBTx *sql.Tx 34 ModuleName string 35 iLog logger.Log 36 User string 37 } 38 39 // NewDBOperation creates a new instance of DBOperation. 40 // It takes the following parameters: 41 // - User: the name of the user performing the database operation. 42 // - DBTx: the SQL transaction object. 43 // - moduleName: the name of the module associated with the database operation. 44 // If moduleName is empty, it defaults to logger.Database. 45 // It returns a pointer to the newly created DBOperation instance. 46 // The function also logs the performance duration of the operation. 47 // If there is an error during the operation, it is recovered and logged as an error. 48 // The function returns a pointer to the newly created DBOperation instance. 49 50 func NewDBOperation(User string, DBTx *sql.Tx, moduleName string) *DBOperation { 51 startTime := time.Now() 52 if moduleName == "" { 53 moduleName = logger.Database 54 } 55 iLog := logger.Log{ModuleName: moduleName, User: User, ControllerName: "Database"} 56 defer func() { 57 elapsed := time.Since(startTime) 58 iLog.PerformanceWithDuration("dbconn.NewDBOperation", elapsed) 59 }() 60 61 return &DBOperation{ 62 DBTx: DBTx, 63 ModuleName: moduleName, 64 iLog: iLog, 65 User: User, 66 } 67 } 68 69 // Query executes a SQL query with optional arguments and returns the resulting rows. 70 // It measures the performance of the query and logs any errors that occur. 71 // If a database transaction is not already in progress, it begins a new transaction. 72 // The transaction is committed if it was started locally. 73 // The returned rows must be closed after use to release associated resources. 74 // The function returns the following parameters: 75 // - rows: the resulting rows. 76 // - err: the error that occurred during the operation. 77 // If there is an error during the operation, it is recovered and logged as an error. 78 // The function returns the resulting rows and any error that occurred during the operation. 79 // The function also logs the performance duration of the operation. 80 81 func (db *DBOperation) Query(querystr string, args ...interface{}) (*sql.Rows, error) { 82 83 startTime := time.Now() 84 defer func() { 85 elapsed := time.Since(startTime) 86 db.iLog.PerformanceWithDuration("dbconn.Query", elapsed) 87 }() 88 89 defer func() { 90 if err := recover(); err != nil { 91 db.iLog.Error(fmt.Sprintf("There is error to query database with error: %s", err)) 92 return 93 } 94 }() 95 96 db.iLog.Debug(fmt.Sprintf("Query: %s %s...", querystr, args)) 97 98 idbtx := db.DBTx 99 blocaltx := false 100 101 if idbtx == nil { 102 idbtx, err = DB.Begin() 103 blocaltx = true 104 if err != nil { 105 db.iLog.Error(fmt.Sprintf("There is error to begin database transaction with error: %s", err.Error())) 106 return nil, err 107 } 108 defer idbtx.Commit() 109 } 110 111 //fmt.Println(string(args)) 112 stmt, err := idbtx.Prepare(querystr) 113 if err != nil { 114 return nil, err 115 } 116 defer stmt.Close() 117 118 rows, err := stmt.Query(args...) 119 120 if err != nil { 121 122 idbtx.Rollback() 123 124 db.iLog.Error(fmt.Sprintf("There is error to query database with error: %s", err.Error())) 125 return nil, err 126 } 127 defer rows.Close() 128 129 if blocaltx { 130 idbtx.Commit() 131 } 132 133 return rows, nil 134 } 135 136 // QuerybyList executes a database query with a list of parameters. 137 // It takes a query string, a list of parameter names, a map of parameter values, and a list of input types. 138 // The function returns a map of query results, the number of rows affected, the number of rows returned, and an error (if any). 139 // The function also logs the performance duration of the operation. 140 // If there is an error during the operation, it is recovered and logged as an error. 141 142 func (db *DBOperation) QuerybyList(querystr string, namelist []string, inputs map[string]interface{}, finputs []types.Input) (map[string][]interface{}, int, int, error) { 143 startTime := time.Now() 144 defer func() { 145 elapsed := time.Since(startTime) 146 db.iLog.PerformanceWithDuration("dbconn.QuerybyList", elapsed) 147 }() 148 defer func() { 149 if err := recover(); err != nil { 150 db.iLog.Error(fmt.Sprintf("There is error to query database with error: %s", err)) 151 return 152 } 153 }() 154 155 db.iLog.Debug(fmt.Sprintf("Query: %s {%s} {%s}", querystr, namelist, inputs)) 156 157 // create a slice to hold the parameter values in the same order as they appear in the SQL query 158 var values []interface{} 159 160 // Execute the SQL statement with the given inputs 161 for i := range namelist { 162 paramPlaceholder := "@" + namelist[i] 163 paramValuePlaceholder := "" 164 switch finputs[i].Datatype { 165 case types.Integer: 166 paramValuePlaceholder = fmt.Sprintf("%d", inputs[namelist[i]]) 167 case types.Float: 168 paramValuePlaceholder = fmt.Sprintf("%f", inputs[namelist[i]]) 169 case types.Bool: 170 paramValuePlaceholder = fmt.Sprintf("%t", inputs[namelist[i]]) 171 default: 172 paramValuePlaceholder = fmt.Sprintf("'%v'", inputs[namelist[i]]) 173 } 174 querystr = strings.Replace(querystr, paramPlaceholder, paramValuePlaceholder, -1) 175 // values = append(values, inputs[namelist[i]]) 176 } 177 178 idbtx := db.DBTx 179 blocaltx := false 180 181 if idbtx == nil { 182 idbtx, err = DB.Begin() 183 blocaltx = true 184 if err != nil { 185 db.iLog.Error(fmt.Sprintf("There is error to begin database transaction with error: %s", err.Error())) 186 return nil, 0, 0, err 187 } 188 defer idbtx.Commit() 189 } 190 191 var stmt *sql.Stmt 192 193 ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(com.DBTransactionTimeout)) 194 defer cancel() 195 stmt, err = idbtx.PrepareContext(ctx, querystr) 196 //stmt, err := idbtx.Prepare(querystr) 197 if err != nil { 198 db.iLog.Error(fmt.Sprintf("There is error to prepare the query: %s with error: %s", querystr, err.Error())) 199 return nil, 0, 0, err 200 } 201 defer stmt.Close() 202 203 rows, err := stmt.QueryContext(ctx, values...) 204 // rows, err := stmt.Query(values...) 205 if err != nil { 206 idbtx.Rollback() 207 db.iLog.Error(fmt.Sprintf("There is error to execute the query: %s with error: %s", querystr, err.Error())) 208 return nil, 0, 0, err 209 } 210 defer rows.Close() 211 212 if blocaltx { 213 idbtx.Commit() 214 } 215 216 return db.Conto_JsonbyList(rows) 217 } 218 219 // Query_Json executes a database query with the provided query string and arguments, 220 // and returns the result as a slice of maps, where each map represents a row of the result set. 221 // The query is executed within a transaction, and the transaction is automatically committed 222 // if it was initiated locally. If an error occurs during the query or conversion to JSON, 223 // the transaction is rolled back and the error is returned. 224 // 225 // Parameters: 226 // - querystr: The query string to execute. 227 // - args: Optional arguments to be passed to the query. 228 // 229 // Returns: 230 // - []map[string]interface{}: The result set as a slice of maps. 231 // - error: Any error that occurred during the query or conversion to JSON. 232 233 func (db *DBOperation) Query_Json(querystr string, args ...interface{}) ([]map[string]interface{}, error) { 234 startTime := time.Now() 235 defer func() { 236 elapsed := time.Since(startTime) 237 db.iLog.PerformanceWithDuration("dbconn.Query_Json", elapsed) 238 }() 239 240 defer func() { 241 if err := recover(); err != nil { 242 db.iLog.Error(fmt.Sprintf("There is error to query database with error: %s", err)) 243 return 244 } 245 }() 246 247 db.iLog.Debug(fmt.Sprintf("Query with json object result: %s %s...", querystr, args)) 248 249 idbtx := db.DBTx 250 blocaltx := false 251 252 if idbtx == nil { 253 idbtx, err = DB.Begin() 254 blocaltx = true 255 if err != nil { 256 db.iLog.Error(fmt.Sprintf("There is error to begin database transaction with error: %s", err.Error())) 257 return nil, err 258 } 259 defer idbtx.Commit() 260 } 261 262 //fmt.Println(string(args)) 263 //stmt, err := idbtx.Prepare(querystr) 264 ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(com.DBTransactionTimeout)) 265 defer cancel() 266 stmt, err := idbtx.PrepareContext(ctx, querystr) 267 if err != nil { 268 return nil, err 269 } 270 defer stmt.Close() 271 272 rows, err := stmt.QueryContext(ctx, args...) 273 //rows, err := stmt.Query(args...) 274 275 if err != nil { 276 idbtx.Rollback() 277 db.iLog.Error(fmt.Sprintf("There is error to query database with error: %s", err.Error())) 278 return nil, err 279 } 280 defer rows.Close() 281 282 db.iLog.Debug(fmt.Sprintf("Query with json object result:%v...", rows)) 283 jsondata, err := db.Conto_Json(rows) 284 if err != nil { 285 idbtx.Rollback() 286 db.iLog.Error(fmt.Sprintf("There is error to convert the rows to json with error: %s", err.Error())) 287 return nil, err 288 } 289 290 if blocaltx { 291 idbtx.Commit() 292 } 293 294 return jsondata, nil 295 } 296 297 // ExecSP executes a stored procedure with the given procedureName and arguments. 298 // It measures the execution time and logs the performance. 299 // If an error occurs during execution, it logs the error and rolls back the transaction. 300 // If a local transaction is used, it commits the transaction at the end. 301 // Parameters: 302 // - procedureName: the name of the stored procedure to execute 303 // - args: the arguments to pass to the stored procedure 304 // Returns: 305 // - error: an error if there was a problem executing the stored procedure 306 307 func (db *DBOperation) ExecSP(procedureName string, args ...interface{}) error { 308 startTime := time.Now() 309 defer func() { 310 elapsed := time.Since(startTime) 311 db.iLog.PerformanceWithDuration("dbconn.ExecSP", elapsed) 312 }() 313 314 defer func() { 315 if err := recover(); err != nil { 316 db.iLog.Error(fmt.Sprintf("There is error to execute store procedure %s in database with error: %s", procedureName, err)) 317 return 318 } 319 }() 320 db.iLog.Debug(fmt.Sprintf("start execute the Store procedure: %s with parameters %s...", procedureName, args)) 321 322 idbtx := db.DBTx 323 blocaltx := false 324 325 if idbtx == nil { 326 idbtx, err = DB.Begin() 327 blocaltx = true 328 if err != nil { 329 db.iLog.Error(fmt.Sprintf("There is error to begin database transaction with error: %s", err.Error())) 330 return err 331 } 332 defer idbtx.Commit() 333 } 334 335 // Construct the stored procedure call with placeholders for each parameter 336 placeholders := make([]string, len(args)) 337 for i := range args { 338 placeholders[i] = "?" 339 } 340 call := fmt.Sprintf("CALL %s(%s)", procedureName, strings.Join(placeholders, ",")) 341 342 db.iLog.Debug(fmt.Sprintf("Call the stored procedure %s with the dynamic parameters %s...", call, args)) 343 344 ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(com.DBTransactionTimeout)) 345 defer cancel() 346 347 // Call the stored procedure with the dynamic parameters 348 _, err := idbtx.ExecContext(ctx, call, args...) 349 //_, err := idbtx.Exec(call, args...) 350 if err != nil { 351 idbtx.Rollback() 352 db.iLog.Error(fmt.Sprintf("There is error to execute the Store procedure: %s with parameters %s with error: %s", procedureName, args, err.Error())) 353 return err 354 } 355 356 if blocaltx { 357 idbtx.Commit() 358 } 359 360 return nil 361 } 362 363 // ExeSPwithRow executes a stored procedure and returns the result set as a *sql.Rows object. 364 // It takes the procedureName as a string and the args as variadic parameters. 365 // The function measures the execution time and logs it using the PerformanceWithDuration method of the db.iLog object. 366 // If there is an error during execution, it logs the error using the Error method of the db.iLog object. 367 // The function handles panics and recovers from them, logging the error if any. 368 // If a database transaction is not already in progress, it begins a new transaction and commits it at the end. 369 // The function constructs the stored procedure call with placeholders for each parameter and the output parameter. 370 // It checks if any of the parameters are output parameters and stores their names in the outputparameters slice. 371 // The function uses the call string to call the stored procedure with the dynamic parameters and the output parameter. 372 // It returns the result set as a *sql.Rows object and nil error if successful, otherwise it returns nil and the error. 373 374 func (db *DBOperation) ExeSPwithRow(procedureName string, args ...interface{}) (*sql.Rows, error) { 375 startTime := time.Now() 376 defer func() { 377 elapsed := time.Since(startTime) 378 db.iLog.PerformanceWithDuration("dbconn.ExeSPwithRow", elapsed) 379 }() 380 381 defer func() { 382 if err := recover(); err != nil { 383 db.iLog.Error(fmt.Sprintf("There is error to execute store procedure %s in database with error: %s", procedureName, err)) 384 return 385 } 386 }() 387 388 // Construct the stored procedure call with placeholders for each parameter and the output parameter 389 db.iLog.Debug(fmt.Sprintf("start execute the Store procedure to return rows: %s with parameters %s...", procedureName, args)) 390 391 idbtx := db.DBTx 392 blocaltx := false 393 394 if idbtx == nil { 395 idbtx, err = DB.Begin() 396 blocaltx = true 397 if err != nil { 398 db.iLog.Error(fmt.Sprintf("There is error to begin database transaction with error: %s", err.Error())) 399 return nil, err 400 } 401 defer idbtx.Commit() 402 } 403 ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(com.DBTransactionTimeout)) 404 defer cancel() 405 406 var outputparameters []string 407 placeholders := make([]string, len(args)) 408 for i := range args { 409 output, parameter := db.chechoutputparameter(args[i].(string)) 410 if output { 411 outputparameters = append(outputparameters, parameter) 412 } 413 placeholders[i] = "?" 414 } 415 //placeholders = append(placeholders, "@output_param") 416 call := fmt.Sprintf("CALL %s(%s)", procedureName, strings.Join(placeholders, ",")) 417 418 // Call the stored procedure with the dynamic parameters and the output parameter 419 420 rows, err := idbtx.QueryContext(ctx, call, args...) 421 //rows, err := idbtx.Query(call, args...) 422 defer rows.Close() 423 424 if err != nil { 425 idbtx.Rollback() 426 db.iLog.Error(fmt.Sprintf("There is error to execute the Store procedure: %s with parameters %s with error: %s", procedureName, args, err.Error())) 427 return nil, err 428 } 429 430 if blocaltx { 431 idbtx.Commit() 432 } 433 434 return rows, nil 435 } 436 437 // ExecSP_Json executes a stored procedure with the given name and arguments, 438 // and returns the result as a slice of maps, where each map represents a row 439 // of the result set. If an error occurs during execution, it returns nil and 440 // the error. 441 // 442 // The execution time of the stored procedure is logged using the PerformanceWithDuration 443 // method of the associated logger. 444 // 445 // If a panic occurs during execution, it is recovered and logged as an error. 446 // 447 // The execution of the stored procedure is logged using the Debug method of the 448 // associated logger. 449 // 450 // The result set is obtained by calling the ExeSPwithRow method of the DBOperation 451 // instance, and the rows are closed before returning. 452 // 453 // If an error occurs during execution, it is logged as an error and returned. 454 // 455 // The result set is converted to a JSON representation using the Conto_Json method 456 // of the DBOperation instance, and returned. 457 458 func (db *DBOperation) ExecSP_Json(procedureName string, args ...interface{}) ([]map[string]interface{}, error) { 459 startTime := time.Now() 460 defer func() { 461 elapsed := time.Since(startTime) 462 db.iLog.PerformanceWithDuration("dbconn.ExecSP_Json", elapsed) 463 }() 464 /* 465 defer func() { 466 if err := recover(); err != nil { 467 db.iLog.Error(fmt.Sprintf("There is error to execute store procedure %s in database with error: %s", procedureName, err)) 468 return 469 } 470 }() 471 */ 472 db.iLog.Debug(fmt.Sprintf("start execute the Store procedure: %s with parameters %s...", procedureName, args)) 473 rows, err := db.ExeSPwithRow(procedureName, args...) 474 defer rows.Close() 475 if err != nil { 476 db.iLog.Error(fmt.Sprintf("There is error to execute the Store procedure: %s with parameters %s with error: %s", procedureName, args, err.Error())) 477 return nil, err 478 } 479 return db.Conto_Json(rows) 480 } 481 482 // chechoutputparameter checks the output parameter of a given string. 483 // It splits the string by space and determines if it contains the word "output". 484 // If it does, it sets the output flag to true and returns the parameter without the word "output". 485 // The function also logs debug messages for the start and result of the check. 486 // It measures the performance duration of the function using the iLog.PerformanceWithDuration method. 487 // If there is a panic during the execution, it logs an error message with the error details. 488 // The function returns a boolean value indicating if the string contains an output parameter, 489 // and the parameter itself without the word "output". 490 491 func (db *DBOperation) chechoutputparameter(str string) (bool, string) { 492 startTime := time.Now() 493 defer func() { 494 elapsed := time.Since(startTime) 495 db.iLog.PerformanceWithDuration("dbconn.chechoutputparameter", elapsed) 496 }() 497 /* 498 defer func() { 499 if err := recover(); err != nil { 500 db.iLog.Error(fmt.Sprintf("There is error to chechoutputparameter with error: %s", err)) 501 return 502 } 503 }() 504 */ 505 db.iLog.Debug(fmt.Sprintf("start to check the output parameter: %s...", str)) 506 output := false 507 parameter := str 508 if strings.Contains(str, " output") { 509 parts := strings.Split(str, " ") 510 output = true 511 parameter = parts[0] 512 513 } 514 db.iLog.Debug(fmt.Sprintf("the output parameter: %s is %s...", parameter, output)) 515 return output, parameter 516 517 } 518 519 // TableInsert inserts data into a specified table in the database. 520 // It takes the table name, column names, and corresponding values as input. 521 // It returns the last insert ID and any error encountered during the operation. 522 // The function measures the performance duration of the operation using the PerformanceWithDuration method of the db.iLog object. 523 func (db *DBOperation) TableInsert(TableName string, Columns []string, Values []string) (int64, error) { 524 startTime := time.Now() 525 defer func() { 526 elapsed := time.Since(startTime) 527 db.iLog.PerformanceWithDuration("dbconn.TableInsert", elapsed) 528 }() 529 530 defer func() { 531 if err := recover(); err != nil { 532 db.iLog.Error(fmt.Sprintf("There is error to execute table %s insert data with error: %s", TableName, err)) 533 return 534 } 535 }() 536 537 db.iLog.Debug(fmt.Sprintf("start to insert the table: %s with columns: %s and values: %s...", TableName, Columns, Values)) 538 539 idbtx := db.DBTx 540 blocaltx := false 541 542 if idbtx == nil { 543 idbtx, err = DB.Begin() 544 blocaltx = true 545 if err != nil { 546 db.iLog.Error(fmt.Sprintf("There is error to begin database transaction with error: %s", err.Error())) 547 return 0, err 548 } 549 defer idbtx.Commit() 550 } 551 ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(com.DBTransactionTimeout)) 552 defer cancel() 553 554 var querystr string 555 556 args := make([]interface{}, len(Values)) 557 querystr = "INSERT INTO " + TableName + "(" + strings.Join(Columns, ",") + ") VALUES (" + strings.Repeat("?,", len(Columns)-1) + "?)" 558 559 for i, s := range Values { 560 args[i] = s 561 } 562 563 fmt.Println(querystr) 564 fmt.Println(args) 565 stmt, err := idbtx.PrepareContext(ctx, querystr) 566 // stmt, err := idbtx.Prepare(querystr) 567 defer stmt.Close() 568 if err != nil { 569 idbtx.Rollback() 570 db.iLog.Error(fmt.Sprintf("There is error to prepare the insert statement with error: %s", err.Error())) 571 return 0, err 572 } 573 res, err := stmt.ExecContext(ctx, args...) 574 //res, err := stmt.Exec(args...) 575 576 if err != nil { 577 idbtx.Rollback() 578 db.iLog.Error(fmt.Sprintf("There is error to execute the insert statement with error: %s", err.Error())) 579 return 0, err 580 } 581 lastId, err := res.LastInsertId() 582 if err != nil { 583 idbtx.Rollback() 584 db.iLog.Error(fmt.Sprintf("There is error to get the last insert id with error: %s", err.Error())) 585 } 586 587 if blocaltx { 588 idbtx.Commit() 589 } 590 591 return lastId, err 592 } 593 594 // TableUpdate updates the specified table with the given columns, values, data types, and WHERE clause. 595 // It returns the number of rows affected and any error encountered during the update operation. 596 // The function measures the performance duration of the operation using the PerformanceWithDuration method of the db.iLog object. 597 // If there is a panic during the execution, it logs an error message with the error details. 598 func (db *DBOperation) TableUpdate(TableName string, Columns []string, Values []string, datatypes []int, Where string) (int64, error) { 599 startTime := time.Now() 600 defer func() { 601 elapsed := time.Since(startTime) 602 db.iLog.PerformanceWithDuration("dbconn.TableUpdate", elapsed) 603 }() 604 605 defer func() { 606 if err := recover(); err != nil { 607 db.iLog.Error(fmt.Sprintf("There is error to execute table %s update data with error: %s", TableName, err)) 608 return 609 } 610 }() 611 db.iLog.Debug(fmt.Sprintf("start to update the table: %s with columns: %s and values: %s data type: %v", TableName, Columns, Values, datatypes)) 612 613 //fmt.Println(WhereArgs) 614 //fmt.Println(Values) 615 var querystr string 616 var args []interface{} 617 618 idbtx := db.DBTx 619 blocaltx := false 620 621 if idbtx == nil { 622 idbtx, err = DB.Begin() 623 blocaltx = true 624 if err != nil { 625 db.iLog.Error(fmt.Sprintf("There is error to begin database transaction with error: %s", err.Error())) 626 return 0, err 627 } 628 defer idbtx.Commit() 629 } 630 ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(com.DBTransactionTimeout)) 631 defer cancel() 632 633 switch DatabaseType { 634 case "sqlserver": 635 setPlaceholders := make([]string, len(Columns)) 636 for i, column := range Columns { 637 638 switch datatypes[i] { 639 case int(types.Integer): 640 setPlaceholders[i] = fmt.Sprintf("%s = %d", column, Values[i]) 641 case int(types.Float): 642 setPlaceholders[i] = fmt.Sprintf("%s = %f", column, Values[i]) 643 644 case int(types.Bool): 645 setPlaceholders[i] = fmt.Sprintf("%s = %t", column, Values[i]) 646 647 default: 648 setPlaceholders[i] = fmt.Sprintf("%s = '%v'", column, Values[i]) 649 650 } 651 652 // setPlaceholders[i] = fmt.Sprintf("%s = '%s'", column, Values[i]) 653 } 654 setClause := strings.Join(setPlaceholders, ", ") 655 querystr := fmt.Sprintf("UPDATE %s SET %s WHERE %s", TableName, setClause, Where) 656 args = []interface{}{} 657 658 db.iLog.Debug(fmt.Sprintf("The update query string is: %s parametrs: %s...", querystr, args)) 659 660 stmt, err := DB.PrepareContext(ctx, querystr) 661 // stmt, err := DB.Prepare(querystr) 662 defer stmt.Close() 663 if err != nil { 664 db.iLog.Error(fmt.Sprintf("There is error to prepare the update statement with error: %s", err.Error())) 665 idbtx.Rollback() 666 return 0, err 667 } 668 669 res, err := stmt.ExecContext(ctx, args...) 670 //res, err := stmt.Exec(args...) 671 if err != nil { 672 db.iLog.Error(fmt.Sprintf("There is error to execute the update statement with error: %s", err.Error())) 673 idbtx.Rollback() 674 return 0, err 675 } 676 677 rowcount, err := res.RowsAffected() 678 if err != nil { 679 db.iLog.Error(fmt.Sprintf("There is error to get the affected rows with error: %s", err.Error())) 680 idbtx.Rollback() 681 return 0, err 682 } 683 684 if blocaltx { 685 idbtx.Commit() 686 } 687 688 return rowcount, err 689 690 default: 691 // case "mysql": 692 693 querystr = "UPDATE " + TableName + " SET " + strings.Join(Columns, "=?,") + "=? WHERE " + Where 694 695 args := make([]interface{}, len(Values)) 696 697 for i, s := range Values { 698 args[i] = s 699 } 700 701 //fmt.Println(querystr) 702 //fmt.Println(args) 703 db.iLog.Debug(fmt.Sprintf("The update query string is: %s parametrs: %s...", querystr, args)) 704 705 stmt, err := idbtx.PrepareContext(ctx, querystr) 706 //stmt, err := idbtx.Prepare(querystr) 707 defer stmt.Close() 708 if err != nil { 709 idbtx.Rollback() 710 db.iLog.Error(fmt.Sprintf("There is error to prepare the update statement with error: %s", err.Error())) 711 return 0, err 712 } 713 res, err := stmt.ExecContext(ctx, args...) 714 //res, err := stmt.Exec(args...) 715 if err != nil { 716 idbtx.Rollback() 717 db.iLog.Error(fmt.Sprintf("There is error to execute the update statement with error: %s", err.Error())) 718 return 0, err 719 } 720 rowcount, err := res.RowsAffected() 721 722 if blocaltx { 723 idbtx.Commit() 724 } 725 726 return rowcount, err 727 } 728 729 } 730 731 // TableDelete deletes records from a table based on the provided WHERE clause. 732 // It returns the number of affected rows and an error, if any. 733 // The function measures the performance duration of the operation using the PerformanceWithDuration method of the db.iLog object. 734 func (db *DBOperation) TableDelete(TableName string, Where string) (int64, error) { 735 startTime := time.Now() 736 defer func() { 737 elapsed := time.Since(startTime) 738 db.iLog.PerformanceWithDuration("dbconn.TableDelete", elapsed) 739 }() 740 741 defer func() { 742 if err := recover(); err != nil { 743 db.iLog.Error(fmt.Sprintf("There is error to execute table %s delete with error: %s", TableName, err)) 744 return 745 } 746 }() 747 748 db.iLog.Debug(fmt.Sprintf("Start to delete the table: %s with where: %s and whereargs: ", TableName, Where)) 749 750 idbtx := db.DBTx 751 blocaltx := false 752 753 if idbtx == nil { 754 idbtx, err = DB.Begin() 755 blocaltx = true 756 if err != nil { 757 db.iLog.Error(fmt.Sprintf("There is error to begin database transaction with error: %s", err.Error())) 758 return 0, err 759 } 760 defer idbtx.Commit() 761 } 762 ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(com.DBTransactionTimeout)) 763 defer cancel() 764 765 var querystr string 766 var args []interface{} 767 querystr = "DELETE FROM " + TableName + " WHERE " + Where 768 769 db.iLog.Debug(fmt.Sprintf("The delete query string is: %s parametrs: %s...", querystr, args)) 770 771 //fmt.Println(querystr) 772 //fmt.Println(args) 773 stmt, err := idbtx.PrepareContext(ctx, querystr) 774 // stmt, err := idbtx.Prepare(querystr) 775 defer stmt.Close() 776 if err != nil { 777 idbtx.Rollback() 778 db.iLog.Error(fmt.Sprintf("There is error to prepare the delete statement with error: %s", err.Error())) 779 return 0, err 780 } 781 res, err := stmt.ExecContext(ctx, args...) 782 // res, err := stmt.Exec(args...) 783 if err != nil { 784 idbtx.Rollback() 785 db.iLog.Error(fmt.Sprintf("There is error to execute the delete statement with error: %s", err.Error())) 786 return 0, err 787 } 788 lastId, err := res.RowsAffected() 789 if err != nil { 790 //idbtx.Commit() 791 db.iLog.Error(fmt.Sprintf("There is error to get the last insert id with error: %s", err.Error())) 792 // return 0, err 793 } 794 795 if blocaltx { 796 idbtx.Commit() 797 } 798 799 return lastId, err 800 } 801 802 func (db *DBOperation) Conto_JsonbyList(rows *sql.Rows) (map[string][]interface{}, int, int, error) { 803 startTime := time.Now() 804 defer func() { 805 elapsed := time.Since(startTime) 806 db.iLog.PerformanceWithDuration("dbconn.Conto_JsonbyList", elapsed) 807 }() 808 /* 809 defer func() { 810 if err := recover(); err != nil { 811 db.iLog.Error(fmt.Sprintf("There is error to Conto_JsonbyList with error: %s", err)) 812 return 813 } 814 }() 815 */ 816 db.iLog.Debug(fmt.Sprintf("Start to convert the rows to json...%s", rows)) 817 cols, err := rows.ColumnTypes() 818 if err != nil { 819 db.iLog.Error(fmt.Sprintf("There is error to get the column types with error: %s", err.Error())) 820 return nil, 0, 0, err 821 } 822 data := make(map[string][]interface{}) 823 colNames := make([]string, len(cols)) 824 valuetmps := make([]interface{}, len(colNames)) 825 826 ColumnNumbers := 0 827 for i, col := range cols { 828 colNames[i] = col.Name() 829 data[col.Name()] = []interface{}{} 830 ColumnNumbers = ColumnNumbers + 1 831 } 832 833 RowNumbers := 0 834 for rows.Next() { 835 values := make([]interface{}, len(colNames)) 836 for i := range values { 837 //values[i] = new(interface{}) 838 values[i] = &valuetmps[i] 839 } 840 err := rows.Scan(values...) 841 if err != nil { 842 db.iLog.Debug(fmt.Sprintf("There is error to scan the row with error: %s", err.Error())) 843 return nil, 0, 0, err 844 845 } 846 for i, name := range colNames { 847 848 var v interface{} 849 850 val := valuetmps[i] 851 b, ok := val.([]byte) 852 if ok { 853 v = string(b) 854 } else { 855 v = val 856 } 857 //data[name] = append(data[name], *(values[i].(*interface{}))) 858 data[name] = append(data[name], v) 859 } 860 RowNumbers = RowNumbers + 1 861 } 862 863 if err := rows.Err(); err != nil { 864 db.iLog.Error(fmt.Sprintf("There is error to get the rows with error: %s", err.Error())) 865 } 866 867 db.iLog.Debug(fmt.Sprintf("The result of the conversion is: %s", data)) 868 869 return data, ColumnNumbers, RowNumbers, nil 870 871 } 872 func (db *DBOperation) Conto_Json(rows *sql.Rows) ([]map[string]interface{}, error) { 873 874 startTime := time.Now() 875 defer func() { 876 elapsed := time.Since(startTime) 877 db.iLog.PerformanceWithDuration("dbconn.Conto_Json", elapsed) 878 }() 879 /* 880 defer func() { 881 if err := recover(); err != nil { 882 db.iLog.Error(fmt.Sprintf("There is error to Conto_Json with error: %s", err)) 883 return 884 } 885 }() 886 */ 887 db.iLog.Debug(fmt.Sprintf("Start to convert the rows to json...%s", rows)) 888 889 cols, err := rows.ColumnTypes() 890 if err != nil { 891 db.iLog.Error(fmt.Sprintf("There is error to get the column types with error: %s", err.Error())) 892 return nil, err 893 894 } 895 896 colNames := make([]string, len(cols)) 897 for i, col := range cols { 898 colNames[i] = col.Name() 899 } 900 data := make([]map[string]interface{}, 0) 901 db.iLog.Debug(fmt.Sprintf("The column names are: %s", colNames)) 902 // db.iLog.Debug(fmt.Sprintf("rows : %s", rows)) 903 valuetmps := make([]interface{}, len(colNames)) 904 905 for rows.Next() { 906 row := make(map[string]interface{}) 907 values := make([]interface{}, len(colNames)) 908 for i := range values { 909 910 values[i] = &valuetmps[i] 911 } 912 913 err := rows.Scan(values...) 914 if err != nil { 915 db.iLog.Error(fmt.Sprintf("There is error to scan the row with error: %s", err.Error())) 916 return nil, err 917 918 } 919 // db.iLog.Debug(fmt.Sprintf("The values of the row is: %s", values)) 920 for i, name := range colNames { 921 var v interface{} 922 val := valuetmps[i] 923 b, ok := val.([]byte) 924 if ok { 925 v = string(b) 926 } else { 927 v = val 928 } 929 // db.iLog.Debug(fmt.Sprintf("The row field %s is: %s", name, v)) 930 row[name] = v 931 //row[name] = *(values[i].(*interface{})) 932 // db.iLog.Debug(fmt.Sprintf("The row field %s is: %s", name, row[name])) 933 } 934 db.iLog.Debug(fmt.Sprintf("The row is: %s", row)) 935 data = append(data, row) 936 } 937 938 if err := rows.Err(); err != nil { 939 db.iLog.Error(fmt.Sprintf("There is error to get the rows with error: %s", err.Error())) 940 } 941 db.iLog.Debug(fmt.Sprintf("The result of the conversion is: %s", data)) 942 //jsondata, err := json.Marshal(data) 943 return data, nil 944 }