docs: def updateFGDBfromSDE(fgdb, sde, logger=None):
      global changes
      """
      fgdb: file geodatabase
      sde: sde geodatabase connection
      logger: agrc.logging.Logger (optional)
  
      returns: String[] - the list of errors
  
      Loops through the file geodatabase feature classes and looks for
      matches in the SDE database. If there is a match, it does a schema check
      and then updates the data.
      """
  
      def log(msg):
          if logger:
              logger.logMsg(msg)
          else:
              print msg
  
      def updateData(isTable):
          try:
              # validate that there was not a schema change
              arcpy.env.workspace = fgdb
              layer = sdeFC + '_Layer'
              if not isTable:
                  arcpy.MakeFeatureLayer_management(sdeFC, layer, '1 = 2')
              else:
                  arcpy.MakeTableView_management(sdeFC, layer, '1 = 2')
  
              try:
                  arcpy.Append_management(layer, f, 'TEST')
                  log('schema test passed')
                  passed = True
              except arcpy.ExecuteError as e:
                  if '000466' in e.message:
                      log(e.message)
                      msg = 'schema change detected'
                      msg += '\n\n{0}'.format(getFieldDifferences(sdeFC, f))
                      errors.append('{}: {}'.format(f, msg))
                      log(msg)
                      passed = False
                      return passed
                  else:
                      raise e
              arcpy.Delete_management(layer)
  
              log('checking for changes...')
              if checkForChanges(f, sdeFC, isTable) and passed:
                  log('updating data...')
                  arcpy.TruncateTable_management(f)
  
                  # edit session required for data that participates in relationships
                  editSession = arcpy.da.Editor(fgdb)
                  editSession.startEditing(False, False)
                  editSession.startOperation()
  
                  fields = [fld.name for fld in arcpy.ListFields(f)]
                  fields = filter_fields(fields)
                  if not isTable:
                      fields.append('SHAPE@')
                      outputSR = arcpy.Describe(f).spatialReference
                  else:
                      outputSR = None
                  with arcpy.da.InsertCursor(f, fields) as icursor, \
                      arcpy.da.SearchCursor(sdeFC, fields, sql_clause=(None, 'ORDER BY OBJECTID'),
                                            spatial_reference=outputSR) as cursor:
                      for row in cursor:
                          icursor.insertRow(row)
  
                  editSession.stopOperation()
                  editSession.stopEditing(True)
  
                  changes.append(f.upper())
              else:
                  log('no changes found')
          except:
              errors.append('Error updating: {}'.format(f))
              if logger:
                  logger.logError()
  
      log('** Updating {} from {}'.format(fgdb, sde))
      errors = []
  
      # loop through local feature classes
      arcpy.env.workspace = fgdb
      fcs = arcpy.ListFeatureClasses() + arcpy.ListTables()
      totalFcs = len(fcs)
      i = 0
      for f in fcs:
          i = i + 1
          log('{} of {} | {}'.format(i, totalFcs, f))
  
          found = False
  
          # search for match in stand-alone feature classes
          arcpy.env.workspace = sde
          matches = arcpy.ListFeatureClasses('*.{}'.format(f)) + arcpy.ListTables('*.{}'.format(f))
          if matches is not None and len(matches) > 0:
              match = matches[0]
              sdeFC = join(sde, match)
              found = True
          else:
              # search in feature datasets
              datasets = arcpy.ListDatasets()
              if len(datasets) > 0:
                  # loop through datasets
                  for ds in datasets:
                      matches = arcpy.ListFeatureClasses('*.{}'.format(f), None, ds)
                      if matches is not None and len(matches) > 0:
                          match = matches[0]
                          sdeFC = join(sde, match)
                          found = True
                          break
          if not found:
              msg = 'no match found in sde'
              errors.append("{}: {}".format(f, msg))
              log(msg)
              continue
  
          updateData(arcpy.Describe(join(fgdb, f)).datasetType == 'Table')
  
      return (errors, changes)