// If we hit an error and there is a pending transaction, rollback // the transaction before returning. The client does not have to // deal with cleaning up transaction state. func makeResultFromError(planMaker *planner, err error) driver.Result { if planMaker.txn != nil { if err != errTransactionAborted { planMaker.txn.Cleanup(err) } // This transaction will normally get marked aborted as part of // Cleanup above, but we do it explicitly here because edge cases // exist: // (1) // BEGIN // <some operation which is implemented using CPut, which fails> // (2) // BEGIN // <syntax error> // Both cases will not write any intents, and so client.Txn will // not actually send an EndTransaction, and rightly so. // Unfortunately, we depend on txn.Proto.Status being equivalent to // our SQL transaction's status, and in these cases, our SQL // transaction is aborted. planMaker.txn.Proto.Status = proto.ABORTED } var errProto proto.Error errProto.SetResponseGoError(err) return driver.Result{Error: &errProto} }
// ServeHTTP serves the SQL API by treating the request URL path // as the method, the request body as the arguments, and sets the // response body as the method reply. The request body is unmarshalled // into arguments based on the Content-Type request header. Protobuf // and JSON-encoded requests are supported. The response body is // encoded according to the request's Accept header, or if not // present, in the same format as the request's incoming Content-Type // header. func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() method := r.URL.Path if !strings.HasPrefix(method, driver.Endpoint) { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) return } // Check TLS settings. authenticationHook, err := security.AuthenticationHook(s.context.Insecure, r.TLS) if err != nil { http.Error(w, err.Error(), http.StatusUnauthorized) return } method = strings.TrimPrefix(method, driver.Endpoint) if method != driver.Execute.String() { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) return } // Unmarshal the request. reqBody, err := ioutil.ReadAll(r.Body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } var args driver.Request if err := util.UnmarshalRequest(r, reqBody, &args, allowedEncodings); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // Check request user against client certificate user. if err := authenticationHook(&args); err != nil { http.Error(w, err.Error(), http.StatusUnauthorized) return } // Send the Request for SQL execution and set the application-level error // on the reply. reply, err := s.exec(args) if err != nil { errProto := proto.Error{} errProto.SetResponseGoError(err) reply.Error = &errProto } // Marshal the response. body, contentType, err := util.MarshalResponse(r, &reply, allowedEncodings) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set(util.ContentTypeHeader, contentType) w.Write(body) }
// If we hit an error and there is a pending transaction, rollback // the transaction before returning. The client does not have to // deal with cleaning up transaction state. func makeResultFromError(planMaker *planner, err error) driver.Result { if planMaker.txn != nil { if err != errTransactionAborted { planMaker.txn.Cleanup(err) } } var errProto proto.Error errProto.SetResponseGoError(err) return driver.Result{Error: &errProto} }
// If we hit an error and there is a pending transaction, rollback // the transaction before returning. The client does not have to // deal with cleaning up transaction state. func rollbackTxnAndReturnResultWithError(planMaker *planner, err error) driver.Result { if planMaker.txn != nil { // What do we do with a rollback error? This is an internally // initiated rollback that the client is unaware of. Reporting it // will only cause confusion. Not reporting it could leave a transaction // pending, but that will get GCed eventually. _ = planMaker.txn.Rollback() } var errProto proto.Error errProto.SetResponseGoError(err) return driver.Result{Error: &errProto} }