Skip to content

Commit

Permalink
[FAB-1917] Fix chaincode query API
Browse files Browse the repository at this point in the history
Address review comments from:
https://gerrit.hyperledger.org/r/#/c/4767/

Updates to logging and comments per Murali's feedback.

Rename ExecuteQuery() to GetQueryResult() per Binh's feedback.
The rename is only made at the top level chaincode function
The name change will be propagated to all the underlying
helper functions and messages as part of a larger refactor that
Murali has planned for post-alpha.

Fix handler.go result type (KV should be QueryRecord).

Tested that chaincode calls to GetQueryResult() work end-to-end.

Change-Id: I9cda95bab237e03880243be0b15110d119f033e8
Signed-off-by: denyeart <enyeart@us.ibm.com>
  • Loading branch information
denyeart committed Jan 29, 2017
1 parent bb41bbc commit 44e7850
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 40 deletions.
36 changes: 18 additions & 18 deletions core/chaincode/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ func (handler *Handler) handleRangeQueryState(msg *pb.ChaincodeMessage) {
}()
}

// afterRangeQueryState handles a RANGE_QUERY_STATE_NEXT request from the chaincode.
// afterQueryStateNext handles a QUERY_STATE_NEXT request from the chaincode.
func (handler *Handler) afterQueryStateNext(e *fsm.Event, state string) {
msg, ok := e.Args[0].(*pb.ChaincodeMessage)
if !ok {
Expand All @@ -725,10 +725,10 @@ func (handler *Handler) afterQueryStateNext(e *fsm.Event, state string) {

// Query ledger for state
handler.handleQueryStateNext(msg)
chaincodeLogger.Debug("Exiting RANGE_QUERY_STATE_NEXT")
chaincodeLogger.Debug("Exiting QUERY_STATE_NEXT")
}

// Handles query to ledger to rage query state next
// Handles query to ledger for query state next
func (handler *Handler) handleQueryStateNext(msg *pb.ChaincodeMessage) {
// The defer followed by triggering a go routine dance is needed to ensure that the previous state transition
// is completed before the next one is triggered. The previous state transition is deemed complete only when
Expand All @@ -754,17 +754,17 @@ func (handler *Handler) handleQueryStateNext(msg *pb.ChaincodeMessage) {
unmarshalErr := proto.Unmarshal(msg.Payload, queryStateNext)
if unmarshalErr != nil {
payload := []byte(unmarshalErr.Error())
chaincodeLogger.Errorf("Failed to unmarshall state range next query request. Sending %s", pb.ChaincodeMessage_ERROR)
chaincodeLogger.Errorf("Failed to unmarshall state next query request. Sending %s", pb.ChaincodeMessage_ERROR)
serialSendMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR, Payload: payload, Txid: msg.Txid}
return
}

txContext := handler.getTxContext(msg.Txid)
rangeIter := handler.getQueryIterator(txContext, queryStateNext.ID)
queryIter := handler.getQueryIterator(txContext, queryStateNext.ID)

if rangeIter == nil {
payload := []byte("Range query iterator not found")
chaincodeLogger.Errorf("Range query iterator not found. Sending %s", pb.ChaincodeMessage_ERROR)
if queryIter == nil {
payload := []byte("query iterator not found")
chaincodeLogger.Errorf("query iterator not found. Sending %s", pb.ChaincodeMessage_ERROR)
serialSendMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR, Payload: payload, Txid: msg.Txid}
return
}
Expand All @@ -775,7 +775,7 @@ func (handler *Handler) handleQueryStateNext(msg *pb.ChaincodeMessage) {
var qresult ledger.QueryResult
var err error
for ; i < maxRangeQueryStateLimit; i++ {
qresult, err = rangeIter.Next()
qresult, err = queryIter.Next()
if err != nil {
chaincodeLogger.Errorf("Failed to get query result from iterator. Sending %s", pb.ChaincodeMessage_ERROR)
return
Expand All @@ -789,14 +789,14 @@ func (handler *Handler) handleQueryStateNext(msg *pb.ChaincodeMessage) {
}

if qresult != nil {
rangeIter.Close()
queryIter.Close()
handler.deleteQueryIterator(txContext, queryStateNext.ID)
}

payload := &pb.QueryStateResponse{KeysAndValues: keysAndValues, HasMore: qresult != nil, ID: queryStateNext.ID}
payloadBytes, err := proto.Marshal(payload)
if err != nil {
rangeIter.Close()
queryIter.Close()
handler.deleteQueryIterator(txContext, queryStateNext.ID)

// Send error msg back to chaincode. GetState will not trigger event
Expand All @@ -812,7 +812,7 @@ func (handler *Handler) handleQueryStateNext(msg *pb.ChaincodeMessage) {
}()
}

// afterRangeQueryState handles a RANGE_QUERY_STATE_CLOSE request from the chaincode.
// afterRangeQueryState handles a QUERY_STATE_CLOSE request from the chaincode.
func (handler *Handler) afterQueryStateClose(e *fsm.Event, state string) {
msg, ok := e.Args[0].(*pb.ChaincodeMessage)
if !ok {
Expand All @@ -823,7 +823,7 @@ func (handler *Handler) afterQueryStateClose(e *fsm.Event, state string) {

// Query ledger for state
handler.handleQueryStateClose(msg)
chaincodeLogger.Debug("Exiting RANGE_QUERY_STATE_CLOSE")
chaincodeLogger.Debug("Exiting QUERY_STATE_CLOSE")
}

// Handles the closing of a state iterator
Expand Down Expand Up @@ -852,7 +852,7 @@ func (handler *Handler) handleQueryStateClose(msg *pb.ChaincodeMessage) {
unmarshalErr := proto.Unmarshal(msg.Payload, queryStateClose)
if unmarshalErr != nil {
payload := []byte(unmarshalErr.Error())
chaincodeLogger.Errorf("Failed to unmarshall state range query close request. Sending %s", pb.ChaincodeMessage_ERROR)
chaincodeLogger.Errorf("Failed to unmarshall state query close request. Sending %s", pb.ChaincodeMessage_ERROR)
serialSendMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR, Payload: payload, Txid: msg.Txid}
return
}
Expand Down Expand Up @@ -923,7 +923,7 @@ func (handler *Handler) handleExecuteQueryState(msg *pb.ChaincodeMessage) {
unmarshalErr := proto.Unmarshal(msg.Payload, executeQueryState)
if unmarshalErr != nil {
payload := []byte(unmarshalErr.Error())
chaincodeLogger.Errorf("Failed to unmarshall range query request. Sending %s", pb.ChaincodeMessage_ERROR)
chaincodeLogger.Errorf("Failed to unmarshall query request. Sending %s", pb.ChaincodeMessage_ERROR)
serialSendMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR, Payload: payload, Txid: msg.Txid}
return
}
Expand All @@ -936,7 +936,7 @@ func (handler *Handler) handleExecuteQueryState(msg *pb.ChaincodeMessage) {
if txContext == nil {
return
}
fmt.Println("==CENDHU==" + executeQueryState.Query)

executeIter, err := txContext.txsimulator.ExecuteQuery(executeQueryState.Query)
if err != nil {
// Send error msg back to chaincode. GetState will not trigger event
Expand All @@ -960,8 +960,8 @@ func (handler *Handler) handleExecuteQueryState(msg *pb.ChaincodeMessage) {
if qresult == nil {
break
}
kv := qresult.(*ledger.KV)
keyAndValue := pb.QueryStateKeyValue{Key: kv.Key, Value: kv.Value}
queryRecord := qresult.(*ledger.QueryRecord)
keyAndValue := pb.QueryStateKeyValue{Key: queryRecord.Key, Value: queryRecord.Record}
keysAndValues = append(keysAndValues, &keyAndValue)
}

Expand Down
7 changes: 6 additions & 1 deletion core/chaincode/shim/chaincode.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,12 @@ func (stub *ChaincodeStub) RangeQueryState(startKey, endKey string) (StateQueryI
return &StateQueryIterator{stub.handler, stub.TxID, response, 0}, nil
}

func (stub *ChaincodeStub) ExecuteQuery(query string) (StateQueryIteratorInterface, error) {
// GetQueryResult function can be invoked by a chaincode to perform a
// rich query against state database. Only supported by state database implementations
// that support rich query. The query string is in the syntax of the underlying
// state database. An iterator is returned which can be used to iterate (next) over
// the query result set
func (stub *ChaincodeStub) GetQueryResult(query string) (StateQueryIteratorInterface, error) {
response, err := stub.handler.handleExecuteQueryState(query, stub.TxID)
if err != nil {
return nil, err
Expand Down
14 changes: 7 additions & 7 deletions core/chaincode/shim/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -552,11 +552,11 @@ func (handler *Handler) handleQueryStateNext(id, txid string) (*pb.QueryStateRes

defer handler.deleteChannel(txid)

// Send RANGE_QUERY_STATE_NEXT message to validator chaincode support
// Send QUERY_STATE_NEXT message to validator chaincode support
payload := &pb.QueryStateNext{ID: id}
payloadBytes, err := proto.Marshal(payload)
if err != nil {
return nil, errors.New("Failed to process range query state next request")
return nil, errors.New("Failed to process query state next request")
}
msg := &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_NEXT, Payload: payloadBytes, Txid: txid}
chaincodeLogger.Debugf("[%s]Sending %s", shorttxid(msg.Txid), pb.ChaincodeMessage_QUERY_STATE_NEXT)
Expand All @@ -574,7 +574,7 @@ func (handler *Handler) handleQueryStateNext(id, txid string) (*pb.QueryStateRes
unmarshalErr := proto.Unmarshal(responseMsg.Payload, queryResponse)
if unmarshalErr != nil {
chaincodeLogger.Errorf("[%s]unmarshall error", shorttxid(responseMsg.Txid))
return nil, errors.New("Error unmarshalling RangeQueryStateResponse.")
return nil, errors.New("Error unmarshalling QueryStateResponse.")
}

return queryResponse, nil
Expand All @@ -600,11 +600,11 @@ func (handler *Handler) handleQueryStateClose(id, txid string) (*pb.QueryStateRe

defer handler.deleteChannel(txid)

// Send RANGE_QUERY_STATE_CLOSE message to validator chaincode support
// Send QUERY_STATE_CLOSE message to validator chaincode support
payload := &pb.QueryStateClose{ID: id}
payloadBytes, err := proto.Marshal(payload)
if err != nil {
return nil, errors.New("Failed to process range query state close request")
return nil, errors.New("Failed to process query state close request")
}
msg := &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_CLOSE, Payload: payloadBytes, Txid: txid}
chaincodeLogger.Debugf("[%s]Sending %s", shorttxid(msg.Txid), pb.ChaincodeMessage_QUERY_STATE_CLOSE)
Expand All @@ -622,7 +622,7 @@ func (handler *Handler) handleQueryStateClose(id, txid string) (*pb.QueryStateRe
unmarshalErr := proto.Unmarshal(responseMsg.Payload, queryResponse)
if unmarshalErr != nil {
chaincodeLogger.Errorf("[%s]unmarshall error", shorttxid(responseMsg.Txid))
return nil, errors.New("Error unmarshalling RangeQueryStateResponse.")
return nil, errors.New("Error unmarshalling QueryStateResponse.")
}

return queryResponse, nil
Expand Down Expand Up @@ -652,7 +652,7 @@ func (handler *Handler) handleExecuteQueryState(query string, txid string) (*pb.
payload := &pb.ExecuteQueryState{Query: query}
payloadBytes, err := proto.Marshal(payload)
if err != nil {
return nil, errors.New("Failed to process range query state request")
return nil, errors.New("Failed to process query state request")
}
msg := &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_EXECUTE_QUERY_STATE, Payload: payloadBytes, Txid: txid}
chaincodeLogger.Debugf("[%s]Sending %s", shorttxid(msg.Txid), pb.ChaincodeMessage_EXECUTE_QUERY_STATE)
Expand Down
29 changes: 17 additions & 12 deletions core/chaincode/shim/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,26 +66,31 @@ type ChaincodeStubInterface interface {
// RangeQueryState function can be invoked by a chaincode to query of a range
// of keys in the state. Assuming the startKey and endKey are in lexical
// an iterator will be returned that can be used to iterate over all keys
// between the startKey and endKey, inclusive. The order in which keys are
// between the startKey (inclusive) and endKey (exclusive). The order in which keys are
// returned by the iterator is random.
RangeQueryState(startKey, endKey string) (StateQueryIteratorInterface, error)

//PartialCompositeKeyQuery function can be invoked by a chaincode to query the
//state based on a given partial composite key. This function returns an
//iterator which can be used to iterate over all composite keys whose prefix
//matches the given partial composite key. This function should be used only for
//a partial composite key. For a full composite key, an iter with empty response
//would be returned.
// PartialCompositeKeyQuery function can be invoked by a chaincode to query the
// state based on a given partial composite key. This function returns an
// iterator which can be used to iterate over all composite keys whose prefix
// matches the given partial composite key. This function should be used only for
// a partial composite key. For a full composite key, an iter with empty response
// would be returned.
PartialCompositeKeyQuery(objectType string, keys []string) (StateQueryIteratorInterface, error)

//Given a list of attributes, CreateCompositeKey function combines these attributes
//to form a composite key.
// Given a list of attributes, CreateCompositeKey function combines these attributes
// to form a composite key.
CreateCompositeKey(objectType string, attributes []string) (string, error)

ExecuteQuery(query string) (StateQueryIteratorInterface, error)
// GetQueryResult function can be invoked by a chaincode to perform a
// rich query against state database. Only supported by state database implementations
// that support rich query. The query string is in the syntax of the underlying
// state database. An iterator is returned which can be used to iterate (next) over
// the query result set
GetQueryResult(query string) (StateQueryIteratorInterface, error)

//Given a composite key, SplitCompositeKey function splits the key into attributes
//on which the composite key was formed.
// Given a composite key, SplitCompositeKey function splits the key into attributes
// on which the composite key was formed.
SplitCompositeKey(compositeKey string) (string, []string, error)

// GetCallerCertificate returns caller certificate
Expand Down
10 changes: 9 additions & 1 deletion core/chaincode/shim/mockstub.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,15 @@ func (stub *MockStub) RangeQueryState(startKey, endKey string) (StateQueryIterat
return NewMockStateRangeQueryIterator(stub, startKey, endKey), nil
}

func (stub *MockStub) ExecuteQuery(query string) (StateQueryIteratorInterface, error) {
// GetQueryResult function can be invoked by a chaincode to perform a
// rich query against state database. Only supported by state database implementations
// that support rich query. The query string is in the syntax of the underlying
// state database. An iterator is returned which can be used to iterate (next) over
// the query result set
func (stub *MockStub) GetQueryResult(query string) (StateQueryIteratorInterface, error) {
// Not implemented since the mock engine does not have a query engine.
// However, a very simple query engine that supports string matching
// could be implemented to test that the framework supports queries
return nil, errors.New("Not Implemented")
}

Expand Down
2 changes: 1 addition & 1 deletion examples/chaincode/go/map/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
return shim.Success(jsonKeys)
case "query":
query := args[0]
keysIter, err := stub.ExecuteQuery(query)
keysIter, err := stub.GetQueryResult(query)
if err != nil {
return shim.Error(fmt.Sprintf("query operation failed. Error accessing state: %s", err))
}
Expand Down

0 comments on commit 44e7850

Please sign in to comment.