本文整理汇总了Golang中github.com/cockroachdb/cockroach/sql/sqlbase.TableDescriptor类的典型用法代码示例。如果您正苦于以下问题:Golang TableDescriptor类的具体用法?Golang TableDescriptor怎么用?Golang TableDescriptor使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了TableDescriptor类的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Golang代码示例。
示例1: writeTableDesc
// writeTableDesc implements the SchemaAccessor interface.
func (p *planner) writeTableDesc(tableDesc *sqlbase.TableDescriptor) error {
if isVirtualDescriptor(tableDesc) {
panic(fmt.Sprintf("Virtual Descriptors cannot be stored, found: %v", tableDesc))
}
return p.txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.GetID()),
sqlbase.WrapDescriptor(tableDesc))
}
开发者ID:yangxuanjia,项目名称:cockroach,代码行数:8,代码来源:table.go
示例2: makeFKDeleteHelper
func makeFKDeleteHelper(
txn *client.Txn, table sqlbase.TableDescriptor, otherTables tableLookupsByID, colMap map[sqlbase.ColumnID]int,
) (fkDeleteHelper, error) {
var fks fkDeleteHelper
for _, idx := range table.AllNonDropIndexes() {
for _, ref := range idx.ReferencedBy {
if otherTables[ref.Table].isAdding {
// We can assume that a table being added but not yet public is empty,
// and thus does not need to be checked for FK violations.
continue
}
fk, err := makeBaseFKHelper(txn, otherTables, idx, ref, colMap)
if err == errSkipUnsedFK {
continue
}
if err != nil {
return fks, err
}
if fks == nil {
fks = make(fkDeleteHelper)
}
fks[idx.ID] = append(fks[idx.ID], fk)
}
}
return fks, nil
}
开发者ID:yangxuanjia,项目名称:cockroach,代码行数:26,代码来源:fk.go
示例3: processColumns
func (p *planner) processColumns(tableDesc *sqlbase.TableDescriptor,
node parser.QualifiedNames) ([]sqlbase.ColumnDescriptor, error) {
if node == nil {
// VisibleColumns is used here to prevent INSERT INTO <table> VALUES (...)
// (as opposed to INSERT INTO <table> (...) VALUES (...)) from writing
// hidden columns. At present, the only hidden column is the implicit rowid
// primary key column.
return tableDesc.VisibleColumns(), nil
}
cols := make([]sqlbase.ColumnDescriptor, len(node))
colIDSet := make(map[sqlbase.ColumnID]struct{}, len(node))
for i, n := range node {
// TODO(pmattis): If the name is qualified, verify the table name matches
// tableDesc.Name.
if err := n.NormalizeColumnName(); err != nil {
return nil, err
}
col, err := tableDesc.FindActiveColumnByName(n.Column())
if err != nil {
return nil, err
}
if _, ok := colIDSet[col.ID]; ok {
return nil, fmt.Errorf("multiple assignments to same column \"%s\"", n.Column())
}
colIDSet[col.ID] = struct{}{}
cols[i] = col
}
return cols, nil
}
开发者ID:GitGoldie,项目名称:cockroach,代码行数:31,代码来源:insert.go
示例4: getKeysForTableDescriptor
// getKeysForTableDescriptor retrieves the KV keys corresponding
// to the zone, name and descriptor of a table.
func getKeysForTableDescriptor(
tableDesc *sqlbase.TableDescriptor,
) (zoneKey roachpb.Key, nameKey roachpb.Key, descKey roachpb.Key) {
zoneKey = sqlbase.MakeZoneKey(tableDesc.ID)
nameKey = sqlbase.MakeNameMetadataKey(tableDesc.ParentID, tableDesc.GetName())
descKey = sqlbase.MakeDescMetadataKey(tableDesc.ID)
return
}
开发者ID:yangxuanjia,项目名称:cockroach,代码行数:10,代码来源:table.go
示例5: makeRowDeleter
// makeRowDeleter creates a rowDeleter for the given table.
//
// The returned rowDeleter contains a fetchCols field that defines the
// expectation of which values are passed as values to deleteRow. Any column
// passed in requestedCols will be included in fetchCols.
func makeRowDeleter(
txn *client.Txn,
tableDesc *sqlbase.TableDescriptor,
fkTables TablesByID,
requestedCols []sqlbase.ColumnDescriptor,
checkFKs bool,
) (rowDeleter, error) {
indexes := tableDesc.Indexes
for _, m := range tableDesc.Mutations {
if index := m.GetIndex(); index != nil {
indexes = append(indexes, *index)
}
}
fetchCols := requestedCols[:len(requestedCols):len(requestedCols)]
fetchColIDtoRowIndex := colIDtoRowIndexFromCols(fetchCols)
maybeAddCol := func(colID sqlbase.ColumnID) error {
if _, ok := fetchColIDtoRowIndex[colID]; !ok {
col, err := tableDesc.FindColumnByID(colID)
if err != nil {
return err
}
fetchColIDtoRowIndex[col.ID] = len(fetchCols)
fetchCols = append(fetchCols, *col)
}
return nil
}
for _, colID := range tableDesc.PrimaryIndex.ColumnIDs {
if err := maybeAddCol(colID); err != nil {
return rowDeleter{}, err
}
}
for _, index := range indexes {
for _, colID := range index.ColumnIDs {
if err := maybeAddCol(colID); err != nil {
return rowDeleter{}, err
}
}
}
rd := rowDeleter{
helper: rowHelper{tableDesc: tableDesc, indexes: indexes},
fetchCols: fetchCols,
fetchColIDtoRowIndex: fetchColIDtoRowIndex,
}
if checkFKs {
var err error
if rd.fks, err = makeFKDeleteHelper(txn, *tableDesc, fkTables, fetchColIDtoRowIndex); err != nil {
return rowDeleter{}, nil
}
}
return rd, nil
}
开发者ID:YuleiXiao,项目名称:cockroach,代码行数:60,代码来源:rowwriter.go
示例6: filterTableState
func filterTableState(tableDesc *sqlbase.TableDescriptor) error {
switch {
case tableDesc.Deleted():
return errTableDeleted
case tableDesc.Adding():
return errTableAdding
case tableDesc.State != sqlbase.TableDescriptor_PUBLIC:
return errors.Errorf("table in unknown state: %s", tableDesc.State.String())
}
return nil
}
开发者ID:yangxuanjia,项目名称:cockroach,代码行数:11,代码来源:table.go
示例7: makeColIDtoRowIndex
func makeColIDtoRowIndex(row planNode, desc *sqlbase.TableDescriptor) (
map[sqlbase.ColumnID]int, error,
) {
columns := row.Columns()
colIDtoRowIndex := make(map[sqlbase.ColumnID]int, len(columns))
for i, column := range columns {
col, err := desc.FindActiveColumnByName(column.Name)
if err != nil {
return nil, err
}
colIDtoRowIndex[col.ID] = i
}
return colIDtoRowIndex, nil
}
开发者ID:GitGoldie,项目名称:cockroach,代码行数:14,代码来源:backfill.go
示例8: deleteIndexMutationsWithReversedColumns
// deleteIndexMutationsWithReversedColumns deletes index mutations with a
// different mutationID than the schema changer and a reference to one of the
// reversed columns.
func (sc *SchemaChanger) deleteIndexMutationsWithReversedColumns(
desc *sqlbase.TableDescriptor, columns map[string]struct{},
) {
newMutations := make([]sqlbase.DescriptorMutation, 0, len(desc.Mutations))
for _, mutation := range desc.Mutations {
if mutation.MutationID != sc.mutationID {
if idx := mutation.GetIndex(); idx != nil {
deleteMutation := false
for _, name := range idx.ColumnNames {
if _, ok := columns[name]; ok {
// Such an index mutation has to be with direction ADD and
// in the DELETE_ONLY state. Live indexes referencing live
// columns cannot be deleted and thus never have direction
// DROP. All mutations with the ADD direction start off in
// the DELETE_ONLY state.
if mutation.Direction != sqlbase.DescriptorMutation_ADD ||
mutation.State != sqlbase.DescriptorMutation_DELETE_ONLY {
panic(fmt.Sprintf("mutation in bad state: %+v", mutation))
}
log.Warningf(context.TODO(), "delete schema change mutation: %+v", mutation)
deleteMutation = true
break
}
}
if deleteMutation {
continue
}
}
}
newMutations = append(newMutations, mutation)
}
// Reset mutations.
desc.Mutations = newMutations
}
开发者ID:yangxuanjia,项目名称:cockroach,代码行数:37,代码来源:schema_changer.go
示例9: convertBatchError
func convertBatchError(tableDesc *sqlbase.TableDescriptor, b *client.Batch) error {
origPErr := b.MustPErr()
if origPErr.Index == nil {
return origPErr.GoError()
}
index := origPErr.Index.Index
if index >= int32(len(b.Results)) {
panic(fmt.Sprintf("index %d outside of results: %+v", index, b.Results))
}
result := b.Results[index]
var alloc sqlbase.DatumAlloc
if _, ok := origPErr.GetDetail().(*roachpb.ConditionFailedError); ok {
for _, row := range result.Rows {
// TODO(dan): There's too much internal knowledge of the sql table
// encoding here (and this callsite is the only reason
// DecodeIndexKeyPrefix is exported). Refactor this bit out.
indexID, key, err := sqlbase.DecodeIndexKeyPrefix(&alloc, tableDesc, row.Key)
if err != nil {
return err
}
index, err := tableDesc.FindIndexByID(indexID)
if err != nil {
return err
}
valTypes, err := sqlbase.MakeKeyVals(tableDesc, index.ColumnIDs)
if err != nil {
return err
}
dirs := make([]encoding.Direction, 0, len(index.ColumnIDs))
for _, dir := range index.ColumnDirections {
convertedDir, err := dir.ToEncodingDirection()
if err != nil {
return err
}
dirs = append(dirs, convertedDir)
}
vals := make([]parser.Datum, len(valTypes))
if _, err := sqlbase.DecodeKeyVals(&alloc, valTypes, vals, dirs, key); err != nil {
return err
}
return sqlbase.NewUniquenessConstraintViolationError(index, vals)
}
}
return origPErr.GoError()
}
开发者ID:yangxuanjia,项目名称:cockroach,代码行数:46,代码来源:errors.go
示例10: makeFKInsertHelper
func makeFKInsertHelper(
txn *client.Txn, table *sqlbase.TableDescriptor, otherTables TablesByID, colMap map[sqlbase.ColumnID]int,
) (fkInsertHelper, error) {
var fks fkInsertHelper
for _, idx := range table.AllNonDropIndexes() {
if idx.ForeignKey != nil {
fk, err := makeBaseFKHelper(txn, otherTables, idx, idx.ForeignKey, colMap)
if err != nil {
return fks, err
}
if fks == nil {
fks = make(fkInsertHelper)
}
fks[idx.ID] = append(fks[idx.ID], fk)
}
}
return fks, nil
}
开发者ID:csdigi,项目名称:cockroach,代码行数:18,代码来源:fk.go
示例11: convertBackfillError
func convertBackfillError(tableDesc *sqlbase.TableDescriptor, b *client.Batch) error {
// A backfill on a new schema element has failed and the batch contains
// information useful in printing a sensible error. However
// convertBatchError() will only work correctly if the schema elements are
// "live" in the tableDesc. Apply the mutations belonging to the same
// mutationID to make all the mutations live in tableDesc. Note: this
// tableDesc is not written to the k:v store.
mutationID := tableDesc.Mutations[0].MutationID
for _, mutation := range tableDesc.Mutations {
if mutation.MutationID != mutationID {
// Mutations are applied in a FIFO order. Only apply the first set
// of mutations if they have the mutation ID we're looking for.
break
}
tableDesc.MakeMutationComplete(mutation)
}
return convertBatchError(tableDesc, b)
}
开发者ID:YuleiXiao,项目名称:cockroach,代码行数:18,代码来源:backfill.go
示例12: makeFKDeleteHelper
func makeFKDeleteHelper(
txn *client.Txn, table *sqlbase.TableDescriptor, otherTables TablesByID, colMap map[sqlbase.ColumnID]int,
) (fkDeleteHelper, error) {
var fks fkDeleteHelper
for _, idx := range table.AllNonDropIndexes() {
for _, ref := range idx.ReferencedBy {
fk, err := makeBaseFKHelper(txn, otherTables, idx, ref, colMap)
if err != nil {
return fks, err
}
if fks == nil {
fks = make(fkDeleteHelper)
}
fks[idx.ID] = append(fks[idx.ID], fk)
}
}
return fks, nil
}
开发者ID:csdigi,项目名称:cockroach,代码行数:18,代码来源:fk.go
示例13: convertBatchError
func convertBatchError(tableDesc *sqlbase.TableDescriptor, b client.Batch, origPErr *roachpb.Error) error {
if origPErr.Index == nil {
return origPErr.GoError()
}
index := origPErr.Index.Index
if index >= int32(len(b.Results)) {
panic(fmt.Sprintf("index %d outside of results: %+v", index, b.Results))
}
result := b.Results[index]
var alloc sqlbase.DatumAlloc
if _, ok := origPErr.GetDetail().(*roachpb.ConditionFailedError); ok {
for _, row := range result.Rows {
indexID, key, err := sqlbase.DecodeIndexKeyPrefix(tableDesc, row.Key)
if err != nil {
return err
}
index, err := tableDesc.FindIndexByID(indexID)
if err != nil {
return err
}
valTypes, err := sqlbase.MakeKeyVals(tableDesc, index.ColumnIDs)
if err != nil {
return err
}
dirs := make([]encoding.Direction, 0, len(index.ColumnIDs))
for _, dir := range index.ColumnDirections {
convertedDir, err := dir.ToEncodingDirection()
if err != nil {
return err
}
dirs = append(dirs, convertedDir)
}
vals := make([]parser.Datum, len(valTypes))
if _, err := sqlbase.DecodeKeyVals(&alloc, valTypes, vals, dirs, key); err != nil {
return err
}
return &errUniquenessConstraintViolation{index: index, vals: vals}
}
}
return origPErr.GoError()
}
开发者ID:GitGoldie,项目名称:cockroach,代码行数:42,代码来源:errors.go
示例14: makeColIDtoRowIndex
func makeColIDtoRowIndex(row planNode, desc *sqlbase.TableDescriptor) (
map[sqlbase.ColumnID]int, error,
) {
columns := row.Columns()
colIDtoRowIndex := make(map[sqlbase.ColumnID]int, len(columns))
for i, column := range columns {
s, idx, err := desc.FindColumnByName(column.Name)
if err != nil {
return nil, err
}
switch s {
case sqlbase.DescriptorActive:
colIDtoRowIndex[desc.Columns[idx].ID] = i
case sqlbase.DescriptorIncomplete:
colIDtoRowIndex[desc.Mutations[idx].GetColumn().ID] = i
default:
panic("unreachable")
}
}
return colIDtoRowIndex, nil
}
开发者ID:YuleiXiao,项目名称:cockroach,代码行数:21,代码来源:backfill.go
示例15: tablesNeededForFKs
// tablesNeededForFKs calculates the IDs of the additional TableDescriptors that
// will be needed for FK checking delete and/or insert operations on `table`.
//
// NB: the returned map's values are *not* set -- higher level calling code, eg
// in planner, should fill the map's values by acquiring leases. This function
// is essentially just returning a slice of IDs, but the empty map can be filled
// in place and reused, avoiding a second allocation.
func tablesNeededForFKs(table sqlbase.TableDescriptor, usage FKCheck) tableLookupsByID {
var ret tableLookupsByID
for _, idx := range table.AllNonDropIndexes() {
if usage != CheckDeletes && idx.ForeignKey.IsSet() {
if ret == nil {
ret = make(tableLookupsByID)
}
ret[idx.ForeignKey.Table] = tableLookup{}
}
if usage != CheckInserts {
for _, idx := range table.AllNonDropIndexes() {
for _, ref := range idx.ReferencedBy {
if ret == nil {
ret = make(tableLookupsByID)
}
ret[ref.Table] = tableLookup{}
}
}
}
}
return ret
}
开发者ID:yangxuanjia,项目名称:cockroach,代码行数:29,代码来源:fk.go
示例16: makeRowDeleter
// makeRowDeleter creates a rowDeleter for the given table.
//
// The returned rowDeleter contains a fetchCols field that defines the
// expectation of which values are passed as values to deleteRow.
func makeRowDeleter(
tableDesc *sqlbase.TableDescriptor,
) (rowDeleter, error) {
// TODO(dan): makeRowDeleter should take a param for the sql rows needed for
// returningHelper, etc.
requestedCols := tableDesc.Columns
indexes := tableDesc.Indexes
for _, m := range tableDesc.Mutations {
if index := m.GetIndex(); index != nil {
indexes = append(indexes, *index)
}
}
fetchCols := requestedCols[:len(requestedCols):len(requestedCols)]
fetchColIDtoRowIndex := colIDtoRowIndexFromCols(fetchCols)
for _, index := range indexes {
for _, colID := range index.ColumnIDs {
if _, ok := fetchColIDtoRowIndex[colID]; !ok {
// TODO(dan): What about non-active columns?
col, err := tableDesc.FindActiveColumnByID(colID)
if err != nil {
return rowDeleter{}, err
}
fetchColIDtoRowIndex[colID] = len(fetchCols)
fetchCols = append(fetchCols, *col)
}
}
}
rd := rowDeleter{
helper: rowHelper{tableDesc: tableDesc, indexes: indexes},
fetchCols: fetchCols,
fetchColIDtoRowIndex: fetchColIDtoRowIndex,
}
return rd, nil
}
开发者ID:GitGoldie,项目名称:cockroach,代码行数:41,代码来源:rowwriter.go
示例17: restoreTable
func restoreTable(
ctx context.Context,
sst engine.RocksDBSstFileReader,
txn *client.Txn,
table *sqlbase.TableDescriptor,
overwrite bool,
) error {
log.Infof(ctx, "Restoring Table %q", table.Name)
tableStartKey := roachpb.Key(sqlbase.MakeIndexKeyPrefix(table, table.PrimaryIndex.ID))
tableEndKey := tableStartKey.PrefixEnd()
existingDesc, err := txn.Get(sqlbase.MakeDescMetadataKey(table.GetID()))
if err != nil {
return err
}
existingData, err := txn.Scan(tableStartKey, tableEndKey, 1)
if err != nil {
return err
}
if existingDesc.Value != nil || len(existingData) > 0 {
if overwrite {
// We're about to Put the descriptor, so don't bother deleting it.
if err := txn.DelRange(tableStartKey, tableEndKey); err != nil {
return err
}
} else {
return errors.Errorf("table %q already exists", table.Name)
}
}
tableDescKey := sqlbase.MakeDescMetadataKey(table.GetID())
if err := txn.Put(tableDescKey, sqlbase.WrapDescriptor(table)); err != nil {
return err
}
return Import(ctx, sst, txn, engine.MVCCKey{Key: tableStartKey}, engine.MVCCKey{Key: tableEndKey})
}
开发者ID:yaojingguo,项目名称:cockroach,代码行数:37,代码来源:backup.go
示例18: processColumns
func (p *planner) processColumns(tableDesc *sqlbase.TableDescriptor,
node parser.UnresolvedNames) ([]sqlbase.ColumnDescriptor, error) {
if node == nil {
// VisibleColumns is used here to prevent INSERT INTO <table> VALUES (...)
// (as opposed to INSERT INTO <table> (...) VALUES (...)) from writing
// hidden columns. At present, the only hidden column is the implicit rowid
// primary key column.
return tableDesc.VisibleColumns(), nil
}
cols := make([]sqlbase.ColumnDescriptor, len(node))
colIDSet := make(map[sqlbase.ColumnID]struct{}, len(node))
for i, n := range node {
c, err := n.NormalizeUnqualifiedColumnItem()
if err != nil {
return nil, err
}
if len(c.Selector) > 0 {
return nil, util.UnimplementedWithIssueErrorf(8318, "compound types not supported yet: %q", n)
}
col, err := tableDesc.FindActiveColumnByName(c.ColumnName)
if err != nil {
return nil, err
}
if _, ok := colIDSet[col.ID]; ok {
return nil, fmt.Errorf("multiple assignments to the same column %q", n)
}
colIDSet[col.ID] = struct{}{}
cols[i] = col
}
return cols, nil
}
开发者ID:yangxuanjia,项目名称:cockroach,代码行数:36,代码来源:insert.go
示例19: makeRowUpdater
// makeRowUpdater creates a rowUpdater for the given table.
//
// updateCols are the columns being updated and correspond to the updateValues
// that will be passed to updateRow.
//
// The returned rowUpdater contains a fetchCols field that defines the
// expectation of which values are passed as oldValues to updateRow. Any column
// passed in requestedCols will be included in fetchCols.
func makeRowUpdater(
txn *client.Txn,
tableDesc *sqlbase.TableDescriptor,
fkTables TablesByID,
updateCols []sqlbase.ColumnDescriptor,
requestedCols []sqlbase.ColumnDescriptor,
updateType rowUpdaterType,
) (rowUpdater, error) {
updateColIDtoRowIndex := colIDtoRowIndexFromCols(updateCols)
primaryIndexCols := make(map[sqlbase.ColumnID]struct{}, len(tableDesc.PrimaryIndex.ColumnIDs))
for _, colID := range tableDesc.PrimaryIndex.ColumnIDs {
primaryIndexCols[colID] = struct{}{}
}
var primaryKeyColChange bool
for _, c := range updateCols {
if _, ok := primaryIndexCols[c.ID]; ok {
primaryKeyColChange = true
break
}
}
// Secondary indexes needing updating.
needsUpdate := func(index sqlbase.IndexDescriptor) bool {
if updateType == rowUpdaterOnlyColumns {
// Only update columns.
return false
}
// If the primary key changed, we need to update all of them.
if primaryKeyColChange {
return true
}
for _, id := range index.ColumnIDs {
if _, ok := updateColIDtoRowIndex[id]; ok {
return true
}
}
return false
}
indexes := make([]sqlbase.IndexDescriptor, 0, len(tableDesc.Indexes)+len(tableDesc.Mutations))
for _, index := range tableDesc.Indexes {
if needsUpdate(index) {
indexes = append(indexes, index)
}
}
var deleteOnlyIndex map[int]struct{}
for _, m := range tableDesc.Mutations {
if index := m.GetIndex(); index != nil {
if needsUpdate(*index) {
indexes = append(indexes, *index)
switch m.State {
case sqlbase.DescriptorMutation_DELETE_ONLY:
if deleteOnlyIndex == nil {
// Allocate at most once.
deleteOnlyIndex = make(map[int]struct{}, len(tableDesc.Mutations))
}
deleteOnlyIndex[len(indexes)-1] = struct{}{}
case sqlbase.DescriptorMutation_WRITE_ONLY:
}
}
}
}
ru := rowUpdater{
helper: rowHelper{tableDesc: tableDesc, indexes: indexes},
updateCols: updateCols,
updateColIDtoRowIndex: updateColIDtoRowIndex,
deleteOnlyIndex: deleteOnlyIndex,
primaryKeyColChange: primaryKeyColChange,
marshalled: make([]roachpb.Value, len(updateCols)),
newValues: make([]parser.Datum, len(tableDesc.Columns)+len(tableDesc.Mutations)),
}
if primaryKeyColChange {
// These fields are only used when the primary key is changing.
var err error
// When changing the primary key, we delete the old values and reinsert
// them, so request them all.
if ru.rd, err = makeRowDeleter(txn, tableDesc, fkTables, tableDesc.Columns, skipFKs); err != nil {
return rowUpdater{}, err
}
ru.fetchCols = ru.rd.fetchCols
ru.fetchColIDtoRowIndex = colIDtoRowIndexFromCols(ru.fetchCols)
if ru.ri, err = makeRowInserter(txn, tableDesc, fkTables, tableDesc.Columns, skipFKs); err != nil {
return rowUpdater{}, err
}
} else {
//.........这里部分代码省略.........
开发者ID:YuleiXiao,项目名称:cockroach,代码行数:101,代码来源:rowwriter.go
示例20: writeTableDesc
// writeTableDesc implements the SchemaAccessor interface.
func (p *planner) writeTableDesc(tableDesc *sqlbase.TableDescriptor) error {
return p.txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.GetID()),
sqlbase.WrapDescriptor(tableDesc))
}
开发者ID:JKhawaja,项目名称:cockroach,代码行数:5,代码来源:table.go
注:本文中的github.com/cockroachdb/cockroach/sql/sqlbase.TableDescriptor类示例整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论