Skip to content

Commit

Permalink
Merge "[FAB-1917] Fix chaincode query API"
Browse files Browse the repository at this point in the history
  • Loading branch information
binhn authored and Gerrit Code Review committed Jan 29, 2017
2 parents 1f1f5f4 + 44e7850 commit 36bbeb6
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 36bbeb6

Please sign in to comment.