github.com/wanlay/gorm-dm8@v1.0.5/dmr/n.go (about) 1 /* 2 * Copyright (c) 2000-2018, 达梦数据库有限公司. 3 * All rights reserved. 4 */ 5 package dmr 6 7 import ( 8 "bytes" 9 "context" 10 "database/sql/driver" 11 "fmt" 12 "net" 13 "net/url" 14 "os" 15 "path/filepath" 16 "regexp" 17 "runtime" 18 "strconv" 19 "strings" 20 "unicode/utf8" 21 22 "github.com/wanlay/gorm-dm8/dmr/util" 23 ) 24 25 const ( 26 TimeZoneKey = "timeZone" 27 EnRsCacheKey = "enRsCache" 28 RsCacheSizeKey = "rsCacheSize" 29 RsRefreshFreqKey = "rsRefreshFreq" 30 LoginPrimary = "loginPrimary" 31 LoginModeKey = "loginMode" 32 LoginStatusKey = "loginStatus" 33 LoginDscCtrlKey = "loginDscCtrl" 34 SwitchTimesKey = "switchTimes" 35 SwitchIntervalKey = "switchInterval" 36 EpSelectorKey = "epSelector" 37 PrimaryKey = "primaryKey" 38 KeywordsKey = "keywords" 39 CompressKey = "compress" 40 CompressIdKey = "compressId" 41 LoginEncryptKey = "loginEncrypt" 42 CommunicationEncryptKey = "communicationEncrypt" 43 DirectKey = "direct" 44 Dec2DoubleKey = "dec2double" 45 RwSeparateKey = "rwSeparate" 46 RwPercentKey = "rwPercent" 47 RwAutoDistributeKey = "rwAutoDistribute" 48 CompatibleModeKey = "compatibleMode" 49 CompatibleOraKey = "comOra" 50 CipherPathKey = "cipherPath" 51 DoSwitchKey = "doSwitch" 52 ClusterKey = "cluster" 53 LanguageKey = "language" 54 DbAliveCheckFreqKey = "dbAliveCheckFreq" 55 RwStandbyRecoverTimeKey = "rwStandbyRecoverTime" 56 LogLevelKey = "logLevel" 57 LogDirKey = "logDir" 58 LogBufferPoolSizeKey = "logBufferPoolSize" 59 LogBufferSizeKey = "logBufferSize" 60 LogFlusherQueueSizeKey = "logFlusherQueueSize" 61 LogFlushFreqKey = "logFlushFreq" 62 StatEnableKey = "statEnable" 63 StatDirKey = "statDir" 64 StatFlushFreqKey = "statFlushFreq" 65 StatHighFreqSqlCountKey = "statHighFreqSqlCount" 66 StatSlowSqlCountKey = "statSlowSqlCount" 67 StatSqlMaxCountKey = "statSqlMaxCount" 68 StatSqlRemoveModeKey = "statSqlRemoveMode" 69 AddressRemapKey = "addressRemap" 70 UserRemapKey = "userRemap" 71 ConnectTimeoutKey = "connectTimeout" 72 LoginCertificateKey = "loginCertificate" 73 UrlKey = "url" 74 HostKey = "host" 75 PortKey = "port" 76 UserKey = "user" 77 PasswordKey = "password" 78 RwStandbyKey = "rwStandby" 79 IsCompressKey = "isCompress" 80 RwHAKey = "rwHA" 81 RwIgnoreSqlKey = "rwIgnoreSql" 82 AppNameKey = "appName" 83 OsNameKey = "osName" 84 MppLocalKey = "mppLocal" 85 SocketTimeoutKey = "socketTimeout" 86 SessionTimeoutKey = "sessionTimeout" 87 ContinueBatchOnErrorKey = "continueBatchOnError" 88 BatchAllowMaxErrorsKey = "batchAllowMaxErrors" 89 EscapeProcessKey = "escapeProcess" 90 AutoCommitKey = "autoCommit" 91 MaxRowsKey = "maxRows" 92 RowPrefetchKey = "rowPrefetch" 93 BufPrefetchKey = "bufPrefetch" 94 LobModeKey = "LobMode" 95 StmtPoolSizeKey = "StmtPoolSize" 96 IgnoreCaseKey = "ignoreCase" 97 AlwayseAllowCommitKey = "AlwayseAllowCommit" 98 BatchTypeKey = "batchType" 99 BatchNotOnCallKey = "batchNotOnCall" 100 IsBdtaRSKey = "isBdtaRS" 101 ClobAsStringKey = "clobAsString" 102 SslCertPathKey = "sslCertPath" 103 SslKeyPathKey = "sslKeyPath" 104 SslFilesPathKey = "sslFilesPath" 105 KerberosLoginConfPathKey = "kerberosLoginConfPath" 106 UKeyNameKey = "uKeyName" 107 UKeyPinKey = "uKeyPin" 108 ColumnNameUpperCaseKey = "columnNameUpperCase" 109 ColumnNameCaseKey = "columnNameCase" 110 DatabaseProductNameKey = "databaseProductName" 111 OsAuthTypeKey = "osAuthType" 112 SchemaKey = "schema" 113 114 TIME_ZONE_DEFAULT int16 = 480 115 116 DO_SWITCH_OFF int32 = 0 117 DO_SWITCH_WHEN_CONN_ERROR int32 = 1 118 DO_SWITCH_WHEN_EP_RECOVER int32 = 2 119 120 CLUSTER_TYPE_NORMAL int32 = 0 121 CLUSTER_TYPE_RW int32 = 1 122 CLUSTER_TYPE_DW int32 = 2 123 CLUSTER_TYPE_DSC int32 = 3 124 CLUSTER_TYPE_MPP int32 = 4 125 126 EP_STATUS_OK int32 = 1 127 EP_STATUS_ERROR int32 = 2 128 129 LOGIN_MODE_PRIMARY_FIRST int32 = 0 130 131 LOGIN_MODE_PRIMARY_ONLY int32 = 1 132 133 LOGIN_MODE_STANDBY_ONLY int32 = 2 134 135 LOGIN_MODE_STANDBY_FIRST int32 = 3 136 137 LOGIN_MODE_NORMAL_FIRST int32 = 4 138 139 SERVER_MODE_NORMAL int32 = 0 140 141 SERVER_MODE_PRIMARY int32 = 1 142 143 SERVER_MODE_STANDBY int32 = 2 144 145 SERVER_STATUS_MOUNT int32 = 3 146 147 SERVER_STATUS_OPEN int32 = 4 148 149 SERVER_STATUS_SUSPEND int32 = 5 150 151 COMPATIBLE_MODE_ORACLE int = 1 152 153 COMPATIBLE_MODE_MYSQL int = 2 154 155 LANGUAGE_CN int = 0 156 157 LANGUAGE_EN int = 1 158 159 COLUMN_NAME_NATURAL_CASE = 0 160 161 COLUMN_NAME_UPPER_CASE = 1 162 163 COLUMN_NAME_LOWER_CASE = 2 164 165 compressDef = Dm_build_681 166 compressIDDef = Dm_build_682 167 168 charCodeDef = "" 169 170 enRsCacheDef = false 171 172 rsCacheSizeDef = 20 173 174 rsRefreshFreqDef = 10 175 176 loginModeDef = LOGIN_MODE_NORMAL_FIRST 177 178 loginStatusDef = 0 179 180 loginEncryptDef = true 181 182 loginCertificateDef = "" 183 184 dec2DoubleDef = false 185 186 rwHADef = false 187 188 rwStandbyDef = false 189 190 rwSeparateDef = false 191 192 rwPercentDef = 25 193 194 rwAutoDistributeDef = true 195 196 rwStandbyRecoverTimeDef = 1000 197 198 cipherPathDef = "" 199 200 urlDef = "" 201 202 userDef = "SYSDBA" 203 204 passwordDef = "SYSDBA" 205 206 hostDef = "localhost" 207 208 portDef = DEFAULT_PORT 209 210 appNameDef = "" 211 212 mppLocalDef = false 213 214 socketTimeoutDef = 0 215 216 connectTimeoutDef = 5000 217 218 sessionTimeoutDef = 0 219 220 osAuthTypeDef = Dm_build_664 221 222 continueBatchOnErrorDef = false 223 224 escapeProcessDef = false 225 226 autoCommitDef = true 227 228 maxRowsDef = 0 229 230 rowPrefetchDef = Dm_build_665 231 232 bufPrefetchDef = 0 233 234 lobModeDef = 1 235 236 stmtPoolMaxSizeDef = 15 237 238 ignoreCaseDef = true 239 240 alwayseAllowCommitDef = true 241 242 isBdtaRSDef = false 243 244 kerberosLoginConfPathDef = "" 245 246 uKeyNameDef = "" 247 248 uKeyPinDef = "" 249 250 databaseProductNameDef = "" 251 252 caseSensitiveDef = true 253 254 compatibleModeDef = 0 255 256 localTimezoneDef = TIME_ZONE_DEFAULT 257 ) 258 259 type DmConnector struct { 260 filterable 261 262 dmDriver *DmDriver 263 264 compress int 265 266 compressID int8 267 268 newClientType bool 269 270 charCode string 271 272 enRsCache bool 273 274 rsCacheSize int 275 276 rsRefreshFreq int 277 278 loginMode int32 279 280 loginStatus int 281 282 loginDscCtrl bool 283 284 switchTimes int32 285 286 switchInterval int 287 288 epSelector int32 289 290 keyWords []string 291 292 loginEncrypt bool 293 294 loginCertificate string 295 296 dec2Double bool 297 298 rwHA bool 299 300 rwStandby bool 301 302 rwSeparate bool 303 304 rwPercent int32 305 306 rwAutoDistribute bool 307 308 rwStandbyRecoverTime int 309 310 rwIgnoreSql bool 311 312 doSwitch int32 313 314 cluster int32 315 316 cipherPath string 317 318 url string 319 320 user string 321 322 password string 323 324 host string 325 326 group *epGroup 327 328 port int32 329 330 appName string 331 332 osName string 333 334 mppLocal bool 335 336 socketTimeout int 337 338 connectTimeout int 339 340 sessionTimeout int 341 342 osAuthType byte 343 344 continueBatchOnError bool 345 346 batchAllowMaxErrors int32 347 348 escapeProcess bool 349 350 autoCommit bool 351 352 maxRows int 353 354 rowPrefetch int 355 356 bufPrefetch int 357 358 lobMode int 359 360 stmtPoolMaxSize int 361 362 ignoreCase bool 363 364 alwayseAllowCommit bool 365 366 batchType int 367 368 batchNotOnCall bool 369 370 isBdtaRS bool 371 372 sslCertPath string 373 374 sslKeyPath string 375 376 sslFilesPath string 377 378 kerberosLoginConfPath string 379 380 uKeyName string 381 382 uKeyPin string 383 384 svcConfPath string 385 386 columnNameCase int 387 388 caseSensitive bool 389 390 compatibleMode int 391 392 localTimezone int16 393 394 schema string 395 396 reConnection *DmConnection 397 398 logLevel int 399 400 logDir string 401 402 logFlushFreq int 403 404 logFlushQueueSize int 405 406 logBufferSize int 407 408 statEnable bool 409 410 statDir string 411 412 statFlushFreq int 413 414 statSlowSqlCount int 415 416 statHighFreqSqlCount int 417 418 statSqlMaxCount int 419 420 statSqlRemoveMode int 421 } 422 423 func (c *DmConnector) init() *DmConnector { 424 c.compress = compressDef 425 c.compressID = compressIDDef 426 c.charCode = charCodeDef 427 c.enRsCache = enRsCacheDef 428 c.rsCacheSize = rsCacheSizeDef 429 c.rsRefreshFreq = rsRefreshFreqDef 430 c.loginMode = loginModeDef 431 c.loginStatus = loginStatusDef 432 c.loginDscCtrl = false 433 c.switchTimes = 1 434 c.switchInterval = 1000 435 c.epSelector = 0 436 c.keyWords = nil 437 c.loginEncrypt = loginEncryptDef 438 c.loginCertificate = loginCertificateDef 439 c.dec2Double = dec2DoubleDef 440 c.rwHA = rwHADef 441 c.rwStandby = rwStandbyDef 442 c.rwSeparate = rwSeparateDef 443 c.rwPercent = rwPercentDef 444 c.rwAutoDistribute = rwAutoDistributeDef 445 c.rwStandbyRecoverTime = rwStandbyRecoverTimeDef 446 c.rwIgnoreSql = false 447 c.doSwitch = DO_SWITCH_OFF 448 c.cluster = CLUSTER_TYPE_NORMAL 449 c.cipherPath = cipherPathDef 450 c.url = urlDef 451 c.user = userDef 452 c.password = passwordDef 453 c.host = hostDef 454 c.port = portDef 455 c.appName = appNameDef 456 c.osName = runtime.GOOS 457 c.mppLocal = mppLocalDef 458 c.socketTimeout = socketTimeoutDef 459 c.connectTimeout = connectTimeoutDef 460 c.sessionTimeout = sessionTimeoutDef 461 c.osAuthType = osAuthTypeDef 462 c.continueBatchOnError = continueBatchOnErrorDef 463 c.batchAllowMaxErrors = 0 464 c.escapeProcess = escapeProcessDef 465 c.autoCommit = autoCommitDef 466 c.maxRows = maxRowsDef 467 c.rowPrefetch = rowPrefetchDef 468 c.bufPrefetch = bufPrefetchDef 469 c.lobMode = lobModeDef 470 c.stmtPoolMaxSize = stmtPoolMaxSizeDef 471 c.ignoreCase = ignoreCaseDef 472 c.alwayseAllowCommit = alwayseAllowCommitDef 473 c.batchType = 1 474 c.batchNotOnCall = false 475 c.isBdtaRS = isBdtaRSDef 476 c.kerberosLoginConfPath = kerberosLoginConfPathDef 477 c.uKeyName = uKeyNameDef 478 c.uKeyPin = uKeyPinDef 479 c.columnNameCase = COLUMN_NAME_NATURAL_CASE 480 c.caseSensitive = caseSensitiveDef 481 c.compatibleMode = compatibleModeDef 482 c.localTimezone = localTimezoneDef 483 c.idGenerator = dmConntorIDGenerator 484 485 c.logDir = LogDirDef 486 c.logFlushFreq = LogFlushFreqDef 487 c.logFlushQueueSize = LogFlushQueueSizeDef 488 c.logBufferSize = LogBufferSizeDef 489 c.statEnable = StatEnableDef 490 c.statDir = StatDirDef 491 c.statFlushFreq = StatFlushFreqDef 492 c.statSlowSqlCount = StatSlowSqlCountDef 493 c.statHighFreqSqlCount = StatHighFreqSqlCountDef 494 c.statSqlMaxCount = StatSqlMaxCountDef 495 c.statSqlRemoveMode = StatSqlRemoveModeDef 496 return c 497 } 498 499 func (c *DmConnector) setAttributes(props *Properties) error { 500 if props == nil || props.Len() == 0 { 501 return nil 502 } 503 504 c.url = props.GetTrimString(UrlKey, c.url) 505 c.host = props.GetTrimString(HostKey, c.host) 506 c.port = int32(props.GetInt(PortKey, int(c.port), 0, 65535)) 507 c.user = props.GetString(UserKey, c.user) 508 c.password = props.GetString(PasswordKey, c.password) 509 c.rwStandby = props.GetBool(RwStandbyKey, c.rwStandby) 510 511 if b := props.GetBool(IsCompressKey, false); b { 512 c.compress = Dm_build_680 513 } 514 515 c.compress = props.GetInt(CompressKey, c.compress, 0, 2) 516 c.compressID = int8(props.GetInt(CompressIdKey, int(c.compressID), 0, 1)) 517 c.enRsCache = props.GetBool(EnRsCacheKey, c.enRsCache) 518 c.localTimezone = int16(props.GetInt(TimeZoneKey, int(c.localTimezone), -720, 720)) 519 c.rsCacheSize = props.GetInt(RsCacheSizeKey, c.rsCacheSize, 0, int(INT32_MAX)) 520 c.rsRefreshFreq = props.GetInt(RsRefreshFreqKey, c.rsRefreshFreq, 0, int(INT32_MAX)) 521 c.loginMode = int32(props.GetInt(LoginModeKey, int(c.loginMode), 0, 4)) 522 c.loginStatus = props.GetInt(LoginStatusKey, c.loginStatus, 0, int(INT32_MAX)) 523 c.loginDscCtrl = props.GetBool(LoginDscCtrlKey, c.loginDscCtrl) 524 c.switchTimes = int32(props.GetInt(SwitchTimesKey, int(c.switchTimes), 0, int(INT32_MAX))) 525 c.switchInterval = props.GetInt(SwitchIntervalKey, c.switchInterval, 0, int(INT32_MAX)) 526 c.epSelector = int32(props.GetInt(EpSelectorKey, int(c.epSelector), 0, 1)) 527 c.loginEncrypt = props.GetBool(LoginEncryptKey, c.loginEncrypt) 528 c.loginCertificate = props.GetTrimString(LoginCertificateKey, c.loginCertificate) 529 c.dec2Double = props.GetBool(Dec2DoubleKey, c.dec2Double) 530 531 c.rwSeparate = props.GetBool(RwSeparateKey, c.rwSeparate) 532 c.rwAutoDistribute = props.GetBool(RwAutoDistributeKey, c.rwAutoDistribute) 533 c.rwPercent = int32(props.GetInt(RwPercentKey, int(c.rwPercent), 0, 100)) 534 c.rwHA = props.GetBool(RwHAKey, c.rwHA) 535 c.rwStandbyRecoverTime = props.GetInt(RwStandbyRecoverTimeKey, c.rwStandbyRecoverTime, 0, int(INT32_MAX)) 536 c.rwIgnoreSql = props.GetBool(RwIgnoreSqlKey, c.rwIgnoreSql) 537 c.doSwitch = int32(props.GetInt(DoSwitchKey, int(c.doSwitch), 0, 2)) 538 c.parseCluster(props) 539 c.cipherPath = props.GetTrimString(CipherPathKey, c.cipherPath) 540 541 if props.GetBool(CompatibleOraKey, false) { 542 c.compatibleMode = int(COMPATIBLE_MODE_ORACLE) 543 } 544 c.parseCompatibleMode(props) 545 c.keyWords = props.GetStringArray(KeywordsKey, c.keyWords) 546 547 c.appName = props.GetTrimString(AppNameKey, c.appName) 548 c.osName = props.GetTrimString(OsNameKey, c.osName) 549 c.mppLocal = props.GetBool(MppLocalKey, c.mppLocal) 550 c.socketTimeout = props.GetInt(SocketTimeoutKey, c.socketTimeout, 0, int(INT32_MAX)) 551 c.connectTimeout = props.GetInt(ConnectTimeoutKey, c.connectTimeout, 0, int(INT32_MAX)) 552 c.sessionTimeout = props.GetInt(SessionTimeoutKey, c.sessionTimeout, 0, int(INT32_MAX)) 553 554 err := c.parseOsAuthType(props) 555 if err != nil { 556 return err 557 } 558 c.continueBatchOnError = props.GetBool(ContinueBatchOnErrorKey, c.continueBatchOnError) 559 c.batchAllowMaxErrors = int32(props.GetInt(BatchAllowMaxErrorsKey, int(c.batchAllowMaxErrors), 0, int(INT32_MAX))) 560 c.escapeProcess = props.GetBool(EscapeProcessKey, c.escapeProcess) 561 c.autoCommit = props.GetBool(AutoCommitKey, c.autoCommit) 562 c.maxRows = props.GetInt(MaxRowsKey, c.maxRows, 0, int(INT32_MAX)) 563 c.rowPrefetch = props.GetInt(RowPrefetchKey, c.rowPrefetch, 0, int(INT32_MAX)) 564 c.bufPrefetch = props.GetInt(BufPrefetchKey, c.bufPrefetch, int(Dm_build_666), int(Dm_build_667)) 565 c.lobMode = props.GetInt(LobModeKey, c.lobMode, 1, 2) 566 c.stmtPoolMaxSize = props.GetInt(StmtPoolSizeKey, c.stmtPoolMaxSize, 0, int(INT32_MAX)) 567 c.ignoreCase = props.GetBool(IgnoreCaseKey, c.ignoreCase) 568 c.alwayseAllowCommit = props.GetBool(AlwayseAllowCommitKey, c.alwayseAllowCommit) 569 c.batchType = props.GetInt(BatchTypeKey, c.batchType, 1, 2) 570 c.batchNotOnCall = props.GetBool(BatchNotOnCallKey, c.batchNotOnCall) 571 c.isBdtaRS = props.GetBool(IsBdtaRSKey, c.isBdtaRS) 572 c.sslFilesPath = props.GetTrimString(SslFilesPathKey, c.sslFilesPath) 573 c.sslCertPath = props.GetTrimString(SslCertPathKey, c.sslCertPath) 574 if c.sslCertPath == "" && c.sslFilesPath != "" { 575 c.sslCertPath = filepath.Join(c.sslFilesPath, "client-cert.pem") 576 } 577 c.sslKeyPath = props.GetTrimString(SslKeyPathKey, c.sslKeyPath) 578 if c.sslKeyPath == "" && c.sslFilesPath != "" { 579 c.sslKeyPath = filepath.Join(c.sslKeyPath, "client-key.pem") 580 } 581 582 c.kerberosLoginConfPath = props.GetTrimString(KerberosLoginConfPathKey, c.kerberosLoginConfPath) 583 584 c.uKeyName = props.GetTrimString(UKeyNameKey, c.uKeyName) 585 c.uKeyPin = props.GetTrimString(UKeyPinKey, c.uKeyPin) 586 587 c.svcConfPath = props.GetString("confPath", "") 588 589 if props.GetBool(ColumnNameUpperCaseKey, false) { 590 c.columnNameCase = COLUMN_NAME_UPPER_CASE 591 } 592 593 v := props.GetTrimString(ColumnNameCaseKey, "") 594 if util.StringUtil.EqualsIgnoreCase(v, "upper") { 595 c.columnNameCase = COLUMN_NAME_UPPER_CASE 596 } else if util.StringUtil.EqualsIgnoreCase(v, "lower") { 597 c.columnNameCase = COLUMN_NAME_LOWER_CASE 598 } 599 600 c.schema = props.GetTrimString(SchemaKey, c.schema) 601 602 c.logLevel = ParseLogLevel(props) 603 LogLevel = c.logLevel 604 c.logDir = util.StringUtil.FormatDir(props.GetTrimString(LogDirKey, LogDirDef)) 605 LogDir = c.logDir 606 c.logBufferSize = props.GetInt(LogBufferSizeKey, LogBufferSizeDef, 1, int(INT32_MAX)) 607 LogBufferSize = c.logBufferSize 608 c.logFlushFreq = props.GetInt(LogFlushFreqKey, LogFlushFreqDef, 1, int(INT32_MAX)) 609 LogFlushFreq = c.logFlushFreq 610 c.logFlushQueueSize = props.GetInt(LogFlusherQueueSizeKey, LogFlushQueueSizeDef, 1, int(INT32_MAX)) 611 LogFlushQueueSize = c.logFlushQueueSize 612 613 c.statEnable = props.GetBool(StatEnableKey, StatEnableDef) 614 StatEnable = c.statEnable 615 c.statDir = util.StringUtil.FormatDir(props.GetTrimString(StatDirKey, StatDirDef)) 616 StatDir = c.statDir 617 c.statFlushFreq = props.GetInt(StatFlushFreqKey, StatFlushFreqDef, 1, int(INT32_MAX)) 618 StatFlushFreq = c.statFlushFreq 619 c.statHighFreqSqlCount = props.GetInt(StatHighFreqSqlCountKey, StatHighFreqSqlCountDef, 0, 1000) 620 StatHighFreqSqlCount = c.statHighFreqSqlCount 621 c.statSlowSqlCount = props.GetInt(StatSlowSqlCountKey, StatSlowSqlCountDef, 0, 1000) 622 StatSlowSqlCount = c.statSlowSqlCount 623 c.statSqlMaxCount = props.GetInt(StatSqlMaxCountKey, StatSqlMaxCountDef, 0, 100000) 624 StatSqlMaxCount = c.statSqlMaxCount 625 c.parseStatSqlRemoveMode(props) 626 return nil 627 } 628 629 func (c *DmConnector) parseOsAuthType(props *Properties) error { 630 value := props.GetString(OsAuthTypeKey, "") 631 if value != "" && !util.StringUtil.IsDigit(value) { 632 if util.StringUtil.EqualsIgnoreCase(value, "ON") { 633 c.osAuthType = Dm_build_664 634 } else if util.StringUtil.EqualsIgnoreCase(value, "SYSDBA") { 635 c.osAuthType = Dm_build_660 636 } else if util.StringUtil.EqualsIgnoreCase(value, "SYSAUDITOR") { 637 c.osAuthType = Dm_build_662 638 } else if util.StringUtil.EqualsIgnoreCase(value, "SYSSSO") { 639 c.osAuthType = Dm_build_661 640 } else if util.StringUtil.EqualsIgnoreCase(value, "AUTO") { 641 c.osAuthType = Dm_build_663 642 } else if util.StringUtil.EqualsIgnoreCase(value, "OFF") { 643 c.osAuthType = Dm_build_659 644 } 645 } else { 646 c.osAuthType = byte(props.GetInt(OsAuthTypeKey, int(c.osAuthType), 0, 4)) 647 } 648 if c.user == "" && c.osAuthType == Dm_build_659 { 649 c.user = "SYSDBA" 650 } else if c.osAuthType != Dm_build_659 && c.user != "" { 651 return ECGO_OSAUTH_ERROR.throw() 652 } else if c.osAuthType != Dm_build_659 { 653 c.user = os.Getenv("user") 654 c.password = "" 655 } 656 return nil 657 } 658 659 func (c *DmConnector) parseCompatibleMode(props *Properties) { 660 value := props.GetString(CompatibleModeKey, "") 661 if value != "" && !util.StringUtil.IsDigit(value) { 662 if util.StringUtil.EqualsIgnoreCase(value, "oracle") { 663 c.compatibleMode = COMPATIBLE_MODE_ORACLE 664 } else if util.StringUtil.EqualsIgnoreCase(value, "mysql") { 665 c.compatibleMode = COMPATIBLE_MODE_MYSQL 666 } 667 } else { 668 c.compatibleMode = props.GetInt(CompatibleModeKey, c.compatibleMode, 0, 2) 669 } 670 } 671 672 func (c *DmConnector) parseStatSqlRemoveMode(props *Properties) { 673 value := props.GetString(StatSqlRemoveModeKey, "") 674 if value != "" && !util.StringUtil.IsDigit(value) { 675 if util.StringUtil.EqualsIgnoreCase("oldest", value) || util.StringUtil.EqualsIgnoreCase("eldest", value) { 676 c.statSqlRemoveMode = STAT_SQL_REMOVE_OLDEST 677 } else if util.StringUtil.EqualsIgnoreCase("latest", value) { 678 c.statSqlRemoveMode = STAT_SQL_REMOVE_LATEST 679 } 680 } else { 681 c.statSqlRemoveMode = props.GetInt(StatSqlRemoveModeKey, StatSqlRemoveModeDef, 1, 2) 682 } 683 } 684 685 func (c *DmConnector) parseCluster(props *Properties) { 686 value := props.GetTrimString(ClusterKey, "") 687 if util.StringUtil.EqualsIgnoreCase(value, "DSC") { 688 c.cluster = CLUSTER_TYPE_DSC 689 } else if util.StringUtil.EqualsIgnoreCase(value, "RW") { 690 c.cluster = CLUSTER_TYPE_RW 691 } else if util.StringUtil.EqualsIgnoreCase(value, "DW") { 692 c.cluster = CLUSTER_TYPE_DW 693 } else if util.StringUtil.EqualsIgnoreCase(value, "MPP") { 694 c.cluster = CLUSTER_TYPE_MPP 695 } else { 696 c.cluster = CLUSTER_TYPE_NORMAL 697 } 698 } 699 700 func (c *DmConnector) parseDSN(dsn string) (*Properties, string, error) { 701 var dsnProps = NewProperties() 702 url, err := url.Parse(dsn) 703 if err != nil { 704 return nil, "", err 705 } 706 if url.Scheme != "dm" { 707 return nil, "", DSN_INVALID_SCHEMA 708 } 709 710 if url.User != nil { 711 c.user = url.User.Username() 712 c.password, _ = url.User.Password() 713 } 714 715 q := url.Query() 716 for k := range q { 717 dsnProps.Set(k, q.Get(k)) 718 } 719 720 return dsnProps, url.Host, nil 721 } 722 723 func (c *DmConnector) BuildDSN() string { 724 var buf bytes.Buffer 725 726 buf.WriteString("dm://") 727 728 if len(c.user) > 0 { 729 buf.WriteString(url.QueryEscape(c.user)) 730 if len(c.password) > 0 { 731 buf.WriteByte(':') 732 buf.WriteString(url.QueryEscape(c.password)) 733 } 734 buf.WriteByte('@') 735 } 736 737 if len(c.host) > 0 { 738 buf.WriteString(c.host) 739 if c.port > 0 { 740 buf.WriteByte(':') 741 buf.WriteString(strconv.Itoa(int(c.port))) 742 } 743 } 744 745 hasParam := false 746 if c.connectTimeout > 0 { 747 if hasParam { 748 buf.WriteString("&timeout=") 749 } else { 750 buf.WriteString("?timeout=") 751 hasParam = true 752 } 753 buf.WriteString(strconv.Itoa(c.connectTimeout)) 754 } 755 return buf.String() 756 } 757 758 func (c *DmConnector) mergeConfigs(dsn string) error { 759 props, host, err := c.parseDSN(dsn) 760 if err != nil { 761 return err 762 } 763 764 driverInit(props.GetString("svcConfPath", "")) 765 766 addressRemapStr := props.GetTrimString(AddressRemapKey, "") 767 userRemapStr := props.GetTrimString(UserRemapKey, "") 768 if addressRemapStr == "" { 769 addressRemapStr = GlobalProperties.GetTrimString(AddressRemapKey, "") 770 } 771 if userRemapStr == "" { 772 userRemapStr = GlobalProperties.GetTrimString(UserRemapKey, "") 773 } 774 775 host = c.remap(host, addressRemapStr) 776 777 c.user = c.remap(c.user, userRemapStr) 778 779 if group, ok := ServerGroupMap[strings.ToLower(host)]; ok { 780 c.group = group 781 } else { 782 host, port, err := net.SplitHostPort(host) 783 errDomain := checkDomain(host) 784 isDomain := errDomain == nil 785 if err != nil || (net.ParseIP(host) == nil && !isDomain) { 786 c.host = hostDef 787 } else { 788 c.host = host 789 } 790 tmpPort, err := strconv.Atoi(port) 791 if err != nil { 792 c.port = portDef 793 } else { 794 c.port = int32(tmpPort) 795 } 796 797 c.group = newEPGroup(c.host+":"+strconv.Itoa(int(c.port)), []*ep{newEP(c.host, c.port)}) 798 } 799 800 props.SetDiffProperties(c.group.props) 801 802 props.SetDiffProperties(GlobalProperties) 803 804 if props.GetBool(RwSeparateKey, false) { 805 props.SetIfNotExist(LoginModeKey, strconv.Itoa(int(LOGIN_MODE_PRIMARY_ONLY))) 806 props.SetIfNotExist(LoginStatusKey, strconv.Itoa(int(SERVER_STATUS_OPEN))) 807 808 props.SetIfNotExist(DoSwitchKey, "true") 809 } 810 811 if err = c.setAttributes(props); err != nil { 812 return err 813 } 814 return nil 815 } 816 817 func (c *DmConnector) remap(origin string, cfgStr string) string { 818 if cfgStr == "" || origin == "" { 819 return origin 820 } 821 822 maps := regexp.MustCompile("\\(.*?,.*?\\)").FindAllString(cfgStr, -1) 823 for _, kvStr := range maps { 824 kv := strings.Split(strings.TrimSpace(kvStr[1:len(kvStr)-1]), ",") 825 if util.StringUtil.Equals(strings.TrimSpace(kv[0]), origin) { 826 return strings.TrimSpace(kv[1]) 827 } 828 } 829 return origin 830 } 831 832 func (c *DmConnector) Connect(ctx context.Context) (driver.Conn, error) { 833 return c.filterChain.reset().DmConnectorConnect(c, ctx) 834 } 835 836 func (c *DmConnector) Driver() driver.Driver { 837 return c.filterChain.reset().DmConnectorDriver(c) 838 } 839 840 func (c *DmConnector) connect(ctx context.Context) (*DmConnection, error) { 841 if c.group != nil && len(c.group.epList) > 0 { 842 return c.group.connect(c) 843 } else { 844 return c.connectSingle(ctx) 845 } 846 } 847 848 func (c *DmConnector) driver() *DmDriver { 849 return c.dmDriver 850 } 851 852 func (c *DmConnector) connectSingle(ctx context.Context) (*DmConnection, error) { 853 var err error 854 var dc *DmConnection 855 if c.reConnection == nil { 856 dc = &DmConnection{ 857 closech: make(chan struct{}), 858 } 859 dc.dmConnector = c 860 dc.autoCommit = c.autoCommit 861 dc.createFilterChain(c, nil) 862 863 dc.objId = -1 864 dc.init() 865 } else { 866 dc = c.reConnection 867 dc.reset() 868 } 869 870 dc.Access, err = dm_build_344(dc) 871 if err != nil { 872 return nil, err 873 } 874 875 dc.startWatcher() 876 if err = dc.watchCancel(ctx); err != nil { 877 return nil, err 878 } 879 defer dc.finish() 880 881 if err = dc.Access.dm_build_385(); err != nil { 882 883 if !dc.closed.IsSet() { 884 close(dc.closech) 885 if dc.Access != nil { 886 dc.Access.Close() 887 } 888 dc.closed.Set(true) 889 } 890 return nil, err 891 } 892 893 if c.schema != "" { 894 _, err = dc.exec("set schema "+c.schema, nil) 895 if err != nil { 896 return nil, err 897 } 898 } 899 900 return dc, nil 901 } 902 903 func checkDomain(name string) error { 904 switch { 905 case len(name) == 0: 906 return nil // an empty domain name will result in a cookie without a domain restriction 907 case len(name) > 255: 908 return fmt.Errorf("cookie domain: name length is %d, can't exceed 255", len(name)) 909 } 910 var l int 911 for i := 0; i < len(name); i++ { 912 b := name[i] 913 if b == '.' { 914 // check domain labels validity 915 switch { 916 case i == l: 917 return fmt.Errorf("cookie domain: invalid character '%c' at offset %d: label can't begin with a period", b, i) 918 case i-l > 63: 919 return fmt.Errorf("cookie domain: byte length of label '%s' is %d, can't exceed 63", name[l:i], i-l) 920 case name[l] == '-': 921 return fmt.Errorf("cookie domain: label '%s' at offset %d begins with a hyphen", name[l:i], l) 922 case name[i-1] == '-': 923 return fmt.Errorf("cookie domain: label '%s' at offset %d ends with a hyphen", name[l:i], l) 924 } 925 l = i + 1 926 continue 927 } 928 // test label character validity, note: tests are ordered by decreasing validity frequency 929 if !(b >= 'a' && b <= 'z' || b >= '0' && b <= '9' || b == '-' || b >= 'A' && b <= 'Z') { 930 // show the printable unicode character starting at byte offset i 931 c, _ := utf8.DecodeRuneInString(name[i:]) 932 if c == utf8.RuneError { 933 return fmt.Errorf("cookie domain: invalid rune at offset %d", i) 934 } 935 return fmt.Errorf("cookie domain: invalid character '%c' at offset %d", c, i) 936 } 937 } 938 // check top level domain validity 939 switch { 940 case l == len(name): 941 return fmt.Errorf("cookie domain: missing top level domain, domain can't end with a period") 942 case len(name)-l > 63: 943 return fmt.Errorf("cookie domain: byte length of top level domain '%s' is %d, can't exceed 63", name[l:], len(name)-l) 944 case name[l] == '-': 945 return fmt.Errorf("cookie domain: top level domain '%s' at offset %d begins with a hyphen", name[l:], l) 946 case name[len(name)-1] == '-': 947 return fmt.Errorf("cookie domain: top level domain '%s' at offset %d ends with a hyphen", name[l:], l) 948 case name[l] >= '0' && name[l] <= '9': 949 return fmt.Errorf("cookie domain: top level domain '%s' at offset %d begins with a digit", name[l:], l) 950 } 951 return nil 952 }