github.com/mithrandie/csvq@v1.18.1/lib/query/processor.go (about) 1 package query 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "os/exec" 8 "strings" 9 "time" 10 11 "github.com/mithrandie/csvq/lib/excmd" 12 "github.com/mithrandie/csvq/lib/option" 13 "github.com/mithrandie/csvq/lib/parser" 14 "github.com/mithrandie/csvq/lib/value" 15 16 "github.com/mithrandie/ternary" 17 ) 18 19 type StatementFlow int 20 21 const ( 22 Terminate StatementFlow = iota 23 TerminateWithError 24 Exit 25 Break 26 Continue 27 Return 28 ) 29 30 const StoringResultsContextKey = "sqr" 31 const StatementReplaceValuesContextKey = "rv" 32 33 func ContextForStoringResults(ctx context.Context) context.Context { 34 return context.WithValue(ctx, StoringResultsContextKey, true) 35 } 36 37 func ContextForPreparedStatement(ctx context.Context, values *ReplaceValues) context.Context { 38 return context.WithValue(ctx, StatementReplaceValuesContextKey, values) 39 } 40 41 type Processor struct { 42 Tx *Transaction 43 ReferenceScope *ReferenceScope 44 45 storeResults bool 46 47 returnVal value.Primary 48 measurementStart time.Time 49 } 50 51 func NewProcessor(tx *Transaction) *Processor { 52 return NewProcessorWithScope(tx, NewReferenceScope(tx)) 53 } 54 55 func NewProcessorWithScope(tx *Transaction, scope *ReferenceScope) *Processor { 56 return &Processor{ 57 Tx: tx, 58 ReferenceScope: scope, 59 } 60 } 61 62 func (proc *Processor) NewChildProcessor() *Processor { 63 return &Processor{ 64 Tx: proc.Tx, 65 ReferenceScope: proc.ReferenceScope.CreateChild(), 66 } 67 } 68 69 func (proc *Processor) Close() { 70 proc.ReferenceScope.CloseCurrentBlock() 71 } 72 73 func (proc *Processor) Execute(ctx context.Context, statements []parser.Statement) (StatementFlow, error) { 74 if v := ctx.Value(StoringResultsContextKey); v != nil { 75 if b, ok := v.(bool); ok && b { 76 proc.storeResults = true 77 } 78 } 79 80 proc.Tx.SelectedViews = nil 81 proc.Tx.AffectedRows = 0 82 83 flow, err := proc.execute(ctx, statements) 84 if err == nil && flow == Terminate && proc.Tx.AutoCommit { 85 err = proc.AutoCommit(ctx) 86 } 87 return flow, err 88 } 89 90 func (proc *Processor) execute(ctx context.Context, statements []parser.Statement) (flow StatementFlow, err error) { 91 defer func() { 92 if err == nil { 93 if panicReport := recover(); panicReport != nil { 94 flow = TerminateWithError 95 err = NewFatalError(panicReport) 96 } 97 } 98 }() 99 100 flow = Terminate 101 102 for _, stmt := range statements { 103 flow, err = proc.ExecuteStatement(ctx, stmt) 104 if err != nil { 105 return 106 } 107 if flow != Terminate { 108 break 109 } 110 } 111 return 112 } 113 114 func (proc *Processor) executeChild(ctx context.Context, statements []parser.Statement) (StatementFlow, error) { 115 child := proc.NewChildProcessor() 116 flow, err := child.execute(ctx, statements) 117 if child.returnVal != nil { 118 proc.returnVal = child.returnVal 119 } 120 child.Close() 121 return flow, err 122 } 123 124 func (proc *Processor) ExecuteStatement(ctx context.Context, stmt parser.Statement) (StatementFlow, error) { 125 if ctx.Err() != nil { 126 return TerminateWithError, ConvertContextError(ctx.Err()) 127 } 128 129 flow := Terminate 130 131 var printstr string 132 var err error 133 134 switch stmt.(type) { 135 case parser.SetFlag: 136 err = SetFlag(ctx, proc.ReferenceScope, stmt.(parser.SetFlag)) 137 case parser.AddFlagElement: 138 err = AddFlagElement(ctx, proc.ReferenceScope, stmt.(parser.AddFlagElement)) 139 case parser.RemoveFlagElement: 140 err = RemoveFlagElement(ctx, proc.ReferenceScope, stmt.(parser.RemoveFlagElement)) 141 case parser.ShowFlag: 142 if printstr, err = ShowFlag(proc.Tx, stmt.(parser.ShowFlag)); err == nil { 143 proc.Log(printstr, false) 144 } 145 case parser.VariableDeclaration: 146 err = proc.ReferenceScope.DeclareVariable(ctx, stmt.(parser.VariableDeclaration)) 147 case parser.VariableSubstitution: 148 _, err = proc.ReferenceScope.SubstituteVariable(ctx, stmt.(parser.VariableSubstitution)) 149 case parser.SetEnvVar: 150 err = SetEnvVar(ctx, proc.ReferenceScope, stmt.(parser.SetEnvVar)) 151 case parser.UnsetEnvVar: 152 err = UnsetEnvVar(stmt.(parser.UnsetEnvVar)) 153 case parser.DisposeVariable: 154 err = proc.ReferenceScope.DisposeVariable(stmt.(parser.DisposeVariable).Variable) 155 case parser.CursorDeclaration: 156 err = proc.ReferenceScope.DeclareCursor(stmt.(parser.CursorDeclaration)) 157 case parser.OpenCursor: 158 openCur := stmt.(parser.OpenCursor) 159 err = proc.ReferenceScope.OpenCursor(ctx, openCur.Cursor, openCur.Values) 160 case parser.CloseCursor: 161 err = proc.ReferenceScope.CloseCursor(stmt.(parser.CloseCursor).Cursor) 162 case parser.DisposeCursor: 163 err = proc.ReferenceScope.DisposeCursor(stmt.(parser.DisposeCursor).Cursor) 164 case parser.FetchCursor: 165 fetch := stmt.(parser.FetchCursor) 166 _, err = FetchCursor(ctx, proc.ReferenceScope, fetch.Cursor, fetch.Position, fetch.Variables) 167 case parser.ViewDeclaration: 168 err = DeclareView(ctx, proc.ReferenceScope, stmt.(parser.ViewDeclaration)) 169 case parser.DisposeView: 170 err = proc.ReferenceScope.DisposeTemporaryTable(stmt.(parser.DisposeView).View) 171 case parser.FunctionDeclaration: 172 err = proc.ReferenceScope.DeclareFunction(stmt.(parser.FunctionDeclaration)) 173 case parser.DisposeFunction: 174 err = proc.ReferenceScope.DisposeFunction(stmt.(parser.DisposeFunction).Name) 175 case parser.AggregateDeclaration: 176 err = proc.ReferenceScope.DeclareAggregateFunction(stmt.(parser.AggregateDeclaration)) 177 case parser.StatementPreparation: 178 err = proc.Tx.PreparedStatements.Prepare(proc.ReferenceScope.Tx.Flags, stmt.(parser.StatementPreparation)) 179 case parser.ExecuteStatement: 180 execStmt := stmt.(parser.ExecuteStatement) 181 prepared, e := proc.Tx.PreparedStatements.Get(execStmt.Name) 182 if e != nil { 183 err = e 184 } else { 185 flow, err = proc.execute(ContextForPreparedStatement(ctx, NewReplaceValues(execStmt.Values)), prepared.Statements) 186 } 187 case parser.DisposeStatement: 188 err = proc.Tx.PreparedStatements.Dispose(stmt.(parser.DisposeStatement)) 189 case parser.SelectQuery: 190 if selectEntity, ok := stmt.(parser.SelectQuery).SelectEntity.(parser.SelectEntity); ok && selectEntity.IntoClause != nil { 191 _, err = Select(ctx, proc.ReferenceScope, stmt.(parser.SelectQuery)) 192 } else { 193 if proc.Tx.Flags.Stats { 194 proc.measurementStart = time.Now() 195 } 196 197 view, e := Select(ctx, proc.ReferenceScope, stmt.(parser.SelectQuery)) 198 if e == nil { 199 var warnmsg string 200 201 proc.Tx.Session.mtx.Lock() 202 203 if proc.storeResults { 204 proc.Tx.SelectedViews = append(proc.Tx.SelectedViews, view) 205 } 206 207 if _, ok := proc.Tx.Session.Stdout().(*Discard); !ok || proc.Tx.Session.OutFile() != nil { 208 exportOptions := proc.Tx.Flags.ExportOptions.Copy() 209 210 var writer io.Writer 211 if proc.Tx.Session.OutFile() != nil { 212 writer = proc.Tx.Session.OutFile() 213 } else { 214 writer = proc.Tx.Session.Stdout() 215 } 216 warn, e := EncodeView(ctx, writer, view, exportOptions, proc.Tx.Palette) 217 218 if e != nil { 219 if e == EmptyResultSetError { 220 warnmsg = warn 221 } else if e == DataEmpty { 222 // Do Nothing 223 } else { 224 err = e 225 } 226 } else if !proc.Tx.Flags.ExportOptions.StripEndingLineBreak && 227 !(proc.Tx.Session.OutFile() != nil && exportOptions.Format == option.FIXED && exportOptions.SingleLine) { 228 _, err = writer.Write([]byte(proc.Tx.Flags.ExportOptions.LineBreak.Value())) 229 } 230 } 231 232 proc.Tx.Session.mtx.Unlock() 233 234 if 0 < len(warnmsg) { 235 proc.LogWarn(warnmsg, proc.Tx.Flags.Quiet) 236 } 237 } else { 238 err = e 239 } 240 241 if proc.Tx.Flags.Stats { 242 proc.showExecutionTime(ctx) 243 } 244 } 245 case parser.InsertQuery: 246 if proc.Tx.Flags.Stats { 247 proc.measurementStart = time.Now() 248 } 249 250 fileInfo, cnt, e := Insert(ctx, proc.ReferenceScope, stmt.(parser.InsertQuery)) 251 if e == nil { 252 if 0 < cnt { 253 proc.Tx.UncommittedViews.SetForUpdatedView(fileInfo) 254 } 255 proc.Log(fmt.Sprintf("%s inserted on %q.", FormatCount(cnt, "record"), fileInfo.Path), proc.Tx.Flags.Quiet) 256 if proc.storeResults { 257 proc.Tx.AffectedRows = cnt 258 } 259 } else { 260 err = e 261 } 262 263 if proc.Tx.Flags.Stats { 264 proc.showExecutionTime(ctx) 265 } 266 case parser.UpdateQuery: 267 if proc.Tx.Flags.Stats { 268 proc.measurementStart = time.Now() 269 } 270 271 infos, cnts, e := Update(ctx, proc.ReferenceScope, stmt.(parser.UpdateQuery)) 272 if e == nil { 273 cntTotal := 0 274 for i, info := range infos { 275 if 0 < cnts[i] { 276 proc.Tx.UncommittedViews.SetForUpdatedView(info) 277 cntTotal += cnts[i] 278 } 279 proc.Log(fmt.Sprintf("%s updated on %q.", FormatCount(cnts[i], "record"), info.Path), proc.Tx.Flags.Quiet) 280 } 281 if proc.storeResults { 282 proc.Tx.AffectedRows = cntTotal 283 } 284 } else { 285 err = e 286 } 287 288 if proc.Tx.Flags.Stats { 289 proc.showExecutionTime(ctx) 290 } 291 case parser.ReplaceQuery: 292 if proc.Tx.Flags.Stats { 293 proc.measurementStart = time.Now() 294 } 295 296 fileInfo, cnt, e := Replace(ctx, proc.ReferenceScope, stmt.(parser.ReplaceQuery)) 297 if e == nil { 298 if 0 < cnt { 299 proc.Tx.UncommittedViews.SetForUpdatedView(fileInfo) 300 } 301 proc.Log(fmt.Sprintf("%s replaced on %q.", FormatCount(cnt, "record"), fileInfo.Path), proc.Tx.Flags.Quiet) 302 if proc.storeResults { 303 proc.Tx.AffectedRows = cnt 304 } 305 } else { 306 err = e 307 } 308 309 if proc.Tx.Flags.Stats { 310 proc.showExecutionTime(ctx) 311 } 312 case parser.DeleteQuery: 313 if proc.Tx.Flags.Stats { 314 proc.measurementStart = time.Now() 315 } 316 317 infos, cnts, e := Delete(ctx, proc.ReferenceScope, stmt.(parser.DeleteQuery)) 318 if e == nil { 319 cntTotal := 0 320 for i, info := range infos { 321 if 0 < cnts[i] { 322 proc.Tx.UncommittedViews.SetForUpdatedView(info) 323 cntTotal += cnts[i] 324 } 325 proc.Log(fmt.Sprintf("%s deleted on %q.", FormatCount(cnts[i], "record"), info.Path), proc.Tx.Flags.Quiet) 326 } 327 if proc.storeResults { 328 proc.Tx.AffectedRows = cntTotal 329 } 330 } else { 331 err = e 332 } 333 334 if proc.Tx.Flags.Stats { 335 proc.showExecutionTime(ctx) 336 } 337 case parser.CreateTable: 338 createTableStatement := stmt.(parser.CreateTable) 339 info, e := CreateTable(ctx, proc.ReferenceScope, createTableStatement) 340 if e == nil { 341 proc.Tx.UncommittedViews.SetForCreatedView(info) 342 proc.Log(fmt.Sprintf("file %q is created.", info.Path), proc.Tx.Flags.Quiet) 343 } else if _, ok := e.(*FileAlreadyExistError); ok && createTableStatement.IfNotExists { 344 e := func() error { 345 filePath, e := CreateFilePath(createTableStatement.Table, proc.ReferenceScope.Tx.Flags.Repository) 346 if e != nil { 347 return NewIOError(createTableStatement.Table, err.Error()) 348 } 349 350 tableIndentifier := parser.Identifier{ 351 BaseExpr: createTableStatement.GetBaseExpr(), 352 Literal: filePath, 353 } 354 355 queryScope := proc.ReferenceScope.CreateNode() 356 defer queryScope.CloseCurrentNode() 357 358 view, e := LoadViewFromTableIdentifier(ctx, queryScope, tableIndentifier, false, false) 359 if e != nil { 360 return e 361 } 362 363 proc.Log(fmt.Sprintf("file %q already exists.", filePath), proc.Tx.Flags.Quiet) 364 365 if createTableStatement.Fields != nil { 366 columns := view.Header.TableColumnNames() 367 368 if len(columns) != len(createTableStatement.Fields) { 369 return NewFieldLengthNotMatchError(createTableStatement.Fields[0]) 370 } 371 372 for _, f := range createTableStatement.Fields { 373 if !InStrSliceWithCaseInsensitive(f.(parser.Identifier).Literal, columns) { 374 return NewFieldNotExistError(f) 375 } 376 } 377 } 378 379 return nil 380 }() 381 382 if e != nil { 383 err = e 384 } 385 } else { 386 err = e 387 } 388 case parser.AddColumns: 389 info, cnt, e := AddColumns(ctx, proc.ReferenceScope, stmt.(parser.AddColumns)) 390 if e == nil { 391 proc.Tx.UncommittedViews.SetForUpdatedView(info) 392 proc.Log(fmt.Sprintf("%s added on %q.", FormatCount(cnt, "field"), info.Path), proc.Tx.Flags.Quiet) 393 } else { 394 err = e 395 } 396 case parser.DropColumns: 397 info, cnt, e := DropColumns(ctx, proc.ReferenceScope, stmt.(parser.DropColumns)) 398 if e == nil { 399 proc.Tx.UncommittedViews.SetForUpdatedView(info) 400 proc.Log(fmt.Sprintf("%s dropped on %q.", FormatCount(cnt, "field"), info.Path), proc.Tx.Flags.Quiet) 401 } else { 402 err = e 403 } 404 case parser.RenameColumn: 405 info, e := RenameColumn(ctx, proc.ReferenceScope, stmt.(parser.RenameColumn)) 406 if e == nil { 407 proc.Tx.UncommittedViews.SetForUpdatedView(info) 408 proc.Log(fmt.Sprintf("%s renamed on %q.", FormatCount(1, "field"), info.Path), proc.Tx.Flags.Quiet) 409 } else { 410 err = e 411 } 412 case parser.SetTableAttribute: 413 expr := stmt.(parser.SetTableAttribute) 414 info, log, e := SetTableAttribute(ctx, proc.ReferenceScope, expr) 415 if e == nil { 416 proc.Tx.UncommittedViews.SetForUpdatedView(info) 417 proc.Log(log, proc.Tx.Flags.Quiet) 418 } else { 419 if unchanged, ok := e.(*TableAttributeUnchangedError); ok { 420 proc.Log(fmt.Sprintf("Table attributes of %s remain unchanged.", unchanged.Path), proc.Tx.Flags.Quiet) 421 } else { 422 err = e 423 } 424 } 425 case parser.TransactionControl: 426 switch stmt.(parser.TransactionControl).Token { 427 case parser.COMMIT: 428 err = proc.Commit(ctx, stmt.(parser.Expression)) 429 case parser.ROLLBACK: 430 err = proc.Rollback(stmt.(parser.Expression)) 431 } 432 case parser.FlowControl: 433 switch stmt.(parser.FlowControl).Token { 434 case parser.CONTINUE: 435 flow = Continue 436 case parser.BREAK: 437 flow = Break 438 } 439 case parser.Exit: 440 ex := stmt.(parser.Exit) 441 code := 0 442 if ex.Code != nil { 443 code = int(ex.Code.(*value.Integer).Raw()) 444 } 445 if 0 < code { 446 flow = TerminateWithError 447 err = NewForcedExit(code) 448 } else { 449 flow = Exit 450 } 451 case parser.Return: 452 var ret value.Primary 453 if ret, err = Evaluate(ctx, proc.ReferenceScope, stmt.(parser.Return).Value); err == nil { 454 proc.returnVal = ret 455 flow = Return 456 } 457 case parser.If: 458 flow, err = proc.IfStmt(ctx, stmt.(parser.If)) 459 case parser.Case: 460 flow, err = proc.Case(ctx, stmt.(parser.Case)) 461 case parser.While: 462 flow, err = proc.While(ctx, stmt.(parser.While)) 463 case parser.WhileInCursor: 464 flow, err = proc.WhileInCursor(ctx, stmt.(parser.WhileInCursor)) 465 case parser.Echo: 466 if printstr, err = Echo(ctx, proc.ReferenceScope, stmt.(parser.Echo)); err == nil { 467 proc.Log(printstr, false) 468 } 469 case parser.Print: 470 if printstr, err = Print(ctx, proc.ReferenceScope, stmt.(parser.Print)); err == nil { 471 proc.Log(printstr, false) 472 } 473 case parser.Printf: 474 if printstr, err = Printf(ctx, proc.ReferenceScope, stmt.(parser.Printf)); err == nil { 475 proc.Log(printstr, false) 476 } 477 case parser.Source: 478 var externalStatements []parser.Statement 479 if externalStatements, err = Source(ctx, proc.ReferenceScope, stmt.(parser.Source)); err == nil { 480 flow, err = proc.execute(ctx, externalStatements) 481 } 482 case parser.Execute: 483 var externalStatements []parser.Statement 484 if externalStatements, err = ParseExecuteStatements(ctx, proc.ReferenceScope, stmt.(parser.Execute)); err == nil { 485 flow, err = proc.execute(ctx, externalStatements) 486 } 487 case parser.Chdir: 488 err = Chdir(ctx, proc.ReferenceScope, stmt.(parser.Chdir)) 489 case parser.Pwd: 490 var dirpath string 491 dirpath, err = Pwd(stmt.(parser.Pwd)) 492 if err == nil { 493 proc.Log(dirpath, false) 494 } 495 case parser.Reload: 496 err = Reload(ctx, proc.Tx, stmt.(parser.Reload)) 497 case parser.ShowObjects: 498 if printstr, err = ShowObjects(proc.ReferenceScope, stmt.(parser.ShowObjects)); err == nil { 499 proc.Log(printstr, false) 500 } 501 case parser.ShowFields: 502 if printstr, err = ShowFields(ctx, proc.ReferenceScope, stmt.(parser.ShowFields)); err == nil { 503 proc.Log(printstr, false) 504 } 505 case parser.Syntax: 506 if printstr, err = Syntax(ctx, proc.ReferenceScope, stmt.(parser.Syntax)); err == nil { 507 proc.Log(printstr, false) 508 } 509 case parser.Trigger: 510 trigger := stmt.(parser.Trigger) 511 switch strings.ToUpper(trigger.Event.Literal) { 512 case "ERROR": 513 var message string 514 if trigger.Message != nil { 515 if pt, ok := trigger.Message.(parser.PrimitiveType); ok && trigger.Code == nil && pt.IsInteger() { 516 trigger.Code = pt.Value 517 } else { 518 var p value.Primary 519 if p, err = Evaluate(ctx, proc.ReferenceScope, trigger.Message); err == nil { 520 if s := value.ToString(p); !value.IsNull(s) { 521 message = s.(*value.String).Raw() 522 } 523 } 524 } 525 } 526 if err == nil { 527 err = NewUserTriggeredError(trigger, message) 528 } 529 default: 530 err = NewInvalidEventNameError(trigger.Event) 531 } 532 case parser.ExternalCommand: 533 err = proc.ExecExternalCommand(ctx, stmt.(parser.ExternalCommand)) 534 default: 535 if expr, ok := stmt.(parser.QueryExpression); ok { 536 _, err = Evaluate(ctx, proc.ReferenceScope, expr) 537 } 538 } 539 540 if err != nil { 541 flow = TerminateWithError 542 } 543 return flow, err 544 } 545 546 func (proc *Processor) IfStmt(ctx context.Context, stmt parser.If) (StatementFlow, error) { 547 stmts := make([]parser.ElseIf, 0, len(stmt.ElseIf)+1) 548 stmts = append(stmts, parser.ElseIf{ 549 Condition: stmt.Condition, 550 Statements: stmt.Statements, 551 }) 552 for _, v := range stmt.ElseIf { 553 stmts = append(stmts, v) 554 } 555 556 for _, v := range stmts { 557 p, err := Evaluate(ctx, proc.ReferenceScope, v.Condition) 558 if err != nil { 559 return TerminateWithError, err 560 } 561 if p.Ternary() == ternary.TRUE { 562 return proc.executeChild(ctx, v.Statements) 563 } 564 } 565 566 if stmt.Else.Statements != nil { 567 return proc.executeChild(ctx, stmt.Else.Statements) 568 } 569 return Terminate, nil 570 } 571 572 func (proc *Processor) Case(ctx context.Context, stmt parser.Case) (StatementFlow, error) { 573 var val value.Primary 574 var err error 575 if stmt.Value != nil { 576 val, err = Evaluate(ctx, proc.ReferenceScope, stmt.Value) 577 if err != nil { 578 return TerminateWithError, err 579 } 580 } 581 582 for _, when := range stmt.When { 583 var t ternary.Value 584 585 cond, err := Evaluate(ctx, proc.ReferenceScope, when.Condition) 586 if err != nil { 587 return TerminateWithError, err 588 } 589 590 if val == nil { 591 t = cond.Ternary() 592 } else { 593 t = value.Equal(val, cond, proc.Tx.Flags.DatetimeFormat, proc.Tx.Flags.GetTimeLocation()) 594 } 595 596 if t == ternary.TRUE { 597 return proc.executeChild(ctx, when.Statements) 598 } 599 } 600 601 if stmt.Else.Statements == nil { 602 return Terminate, nil 603 } 604 return proc.executeChild(ctx, stmt.Else.Statements) 605 } 606 607 func (proc *Processor) While(ctx context.Context, stmt parser.While) (StatementFlow, error) { 608 childProc := proc.NewChildProcessor() 609 defer childProc.Close() 610 611 for { 612 childProc.ReferenceScope.ClearCurrentBlock() 613 p, err := Evaluate(ctx, childProc.ReferenceScope, stmt.Condition) 614 if err != nil { 615 return TerminateWithError, err 616 } 617 if p.Ternary() != ternary.TRUE { 618 break 619 } 620 621 f, err := childProc.execute(ctx, stmt.Statements) 622 if err != nil { 623 return TerminateWithError, err 624 } 625 626 switch f { 627 case Break: 628 return Terminate, nil 629 case Exit: 630 return Exit, nil 631 case Return: 632 proc.returnVal = childProc.returnVal 633 return Return, nil 634 } 635 } 636 return Terminate, nil 637 } 638 639 func (proc *Processor) WhileInCursor(ctx context.Context, stmt parser.WhileInCursor) (StatementFlow, error) { 640 fetchPosition := parser.FetchPosition{ 641 Position: parser.Token{Token: parser.NEXT}, 642 } 643 644 childProc := proc.NewChildProcessor() 645 defer childProc.Close() 646 647 for { 648 childProc.ReferenceScope.ClearCurrentBlock() 649 if stmt.WithDeclaration { 650 assigns := make([]parser.VariableAssignment, len(stmt.Variables)) 651 for i, v := range stmt.Variables { 652 assigns[i] = parser.VariableAssignment{Variable: v} 653 } 654 decl := parser.VariableDeclaration{Assignments: assigns} 655 if err := childProc.ReferenceScope.DeclareVariable(ctx, decl); err != nil { 656 return TerminateWithError, err 657 } 658 } 659 660 success, err := FetchCursor(ctx, childProc.ReferenceScope, stmt.Cursor, fetchPosition, stmt.Variables) 661 if err != nil { 662 return TerminateWithError, err 663 } 664 if !success { 665 break 666 } 667 668 f, err := childProc.execute(ctx, stmt.Statements) 669 if err != nil { 670 return TerminateWithError, err 671 } 672 673 switch f { 674 case Break: 675 return Terminate, nil 676 case Exit: 677 return Exit, nil 678 case Return: 679 proc.returnVal = childProc.returnVal 680 return Return, nil 681 } 682 } 683 684 return Terminate, nil 685 } 686 687 func (proc *Processor) ExecExternalCommand(ctx context.Context, stmt parser.ExternalCommand) error { 688 splitter := new(excmd.ArgsSplitter).Init(stmt.Command) 689 var argStrs = make([]string, 0, 8) 690 for splitter.Scan() { 691 argStrs = append(argStrs, splitter.Text()) 692 } 693 err := splitter.Err() 694 if err != nil { 695 return NewExternalCommandError(stmt, err.Error()) 696 } 697 698 args := make([]string, 0, len(argStrs)) 699 for _, argStr := range argStrs { 700 arg, err := EvaluateEmbeddedString(ctx, proc.ReferenceScope, argStr) 701 if err != nil { 702 if appErr, ok := err.(Error); ok { 703 err = NewExternalCommandError(stmt, appErr.Message()) 704 } else { 705 err = NewExternalCommandError(stmt, err.Error()) 706 } 707 return err 708 } 709 args = append(args, arg) 710 } 711 712 if len(args) < 1 { 713 return nil 714 } 715 716 c := exec.Command(args[0], args[1:]...) 717 c.Stdin = proc.Tx.Session.Stdin() 718 c.Stdout = proc.Tx.Session.Stdout() 719 c.Stderr = proc.Tx.Session.Stderr() 720 721 err = c.Run() 722 if err != nil { 723 err = NewExternalCommandError(stmt, err.Error()) 724 } 725 return err 726 } 727 728 func (proc *Processor) showExecutionTime(ctx context.Context) { 729 if ctx.Err() != nil { 730 return 731 } 732 733 exectime := option.FormatNumber(time.Since(proc.measurementStart).Seconds(), 6, ".", ",", "") 734 stats := fmt.Sprintf(proc.Tx.Palette.Render(option.LableEffect, "Query Execution Time: ")+"%s seconds", exectime) 735 proc.Log(stats, false) 736 } 737 738 func (proc *Processor) Log(log string, quiet bool) { 739 proc.Tx.Log(log, quiet) 740 } 741 742 func (proc *Processor) LogNotice(log string, quiet bool) { 743 proc.Tx.LogNotice(log, quiet) 744 } 745 746 func (proc *Processor) LogWarn(log string, quiet bool) { 747 proc.Tx.LogWarn(log, quiet) 748 } 749 750 func (proc *Processor) LogError(log string) { 751 proc.Tx.LogError(log) 752 } 753 754 func (proc *Processor) AutoCommit(ctx context.Context) error { 755 return proc.Commit(ctx, nil) 756 } 757 758 func (proc *Processor) Commit(ctx context.Context, expr parser.Expression) error { 759 return proc.Tx.Commit(ctx, proc.ReferenceScope, expr) 760 } 761 762 func (proc *Processor) AutoRollback() error { 763 return proc.Rollback(nil) 764 } 765 766 func (proc *Processor) Rollback(expr parser.Expression) error { 767 return proc.Tx.Rollback(proc.ReferenceScope, expr) 768 } 769 770 func (proc *Processor) ReleaseResources() error { 771 return proc.Tx.ReleaseResources() 772 } 773 774 func (proc *Processor) ReleaseResourcesWithErrors() error { 775 return proc.Tx.ReleaseResourcesWithErrors() 776 }