| 
 | 1 | +# PostgreSQL 12 to 16 Schema Drift  | 
 | 2 | + | 
 | 3 | +In Sourcegraph versions `5.10.x` and `5.11.x` we support both PostgreSQL 12 and 16. However, Sourcegraph's database management tool `migrator` expects the database schema of the various Sourcegraph databases to be in an exact expected state. The upgrade from PostgreSQL 12 to 16 is opinionated and automatically mutates the schema without running our application defined migrations. Starting in Sourcegraph `5.10.0` we expect databases to be in PosttgresSQL 16 and as such our tooling will identify schema drift in PostgreSQL 12 databases. This drift does not impact the functionality of the Sourcegraph instance but will stop migrator's multiversion `upgrade` command and `autoupgrade` from executing.  | 
 | 4 | + | 
 | 5 | +The drift takes the following general form, dropping table prefixes to columns in views, and changing `uuid` types to `gen_random_uuid()`:  | 
 | 6 | +```diff  | 
 | 7 | +Schema drift detected in 8 objects:  | 
 | 8 | + | 
 | 9 | +webhooks.uuid:  | 
 | 10 | +Problem: Unexpected properties of column webhooks."uuid"  | 
 | 11 | +Solution: alter the column  | 
 | 12 | +Statement: ALTER TABLE webhooks ALTER COLUMN uuid SET DEFAULT public.gen_random_uuid();  | 
 | 13 | + | 
 | 14 | +batch_spec_workspace_execution_queue:  | 
 | 15 | +Problem: Unexpected definition of view "batch_spec_workspace_execution_queue"  | 
 | 16 | +Solution: redefine the view  | 
 | 17 | +Diff:  | 
 | 18 | +  (  | 
 | 19 | +  	"""  | 
 | 20 | +  	... // 6 identical lines  | 
 | 21 | +  	          ORDER BY (rank() OVER (PARTITION BY queue.user_id ORDER BY exec.created_at, exec.id)), queue.latest_dequeue NULLS FIRST  | 
 | 22 | +  	        )  | 
 | 23 | +- 	 SELECT id,  | 
 | 24 | ++ 	 SELECT queue_candidates.id,  | 
 | 25 | +  	    row_number() OVER () AS place_in_global_queue,  | 
 | 26 | +- 	    place_in_user_queue  | 
 | 27 | ++ 	    queue_candidates.place_in_user_queue  | 
 | 28 | +  	   FROM queue_candidates;  | 
 | 29 | +  	"""  | 
 | 30 | +  )  | 
 | 31 | + | 
 | 32 | +codeintel_configuration_policies:  | 
 | 33 | +Problem: Unexpected definition of view "codeintel_configuration_policies"  | 
 | 34 | +Solution: redefine the view  | 
 | 35 | +Diff:  | 
 | 36 | +  (  | 
 | 37 | +  	"""  | 
 | 38 | +- 	 SELECT id,  | 
 | 39 | +- 	    repository_id,  | 
 | 40 | +- 	    name,  | 
 | 41 | +- 	    type,  | 
 | 42 | +- 	    pattern,  | 
 | 43 | +- 	    retention_enabled,  | 
 | 44 | +- 	    retention_duration_hours,  | 
 | 45 | +- 	    retain_intermediate_commits,  | 
 | 46 | +- 	    indexing_enabled,  | 
 | 47 | +- 	    index_commit_max_age_hours,  | 
 | 48 | +- 	    index_intermediate_commits,  | 
 | 49 | +- 	    protected,  | 
 | 50 | +- 	    repository_patterns,  | 
 | 51 | +- 	    last_resolved_at,  | 
 | 52 | +- 	    embeddings_enabled  | 
 | 53 | ++ 	 SELECT lsif_configuration_policies.id,  | 
 | 54 | ++ 	    lsif_configuration_policies.repository_id,  | 
 | 55 | ++ 	    lsif_configuration_policies.name,  | 
 | 56 | ++ 	    lsif_configuration_policies.type,  | 
 | 57 | ++ 	    lsif_configuration_policies.pattern,  | 
 | 58 | ++ 	    lsif_configuration_policies.retention_enabled,  | 
 | 59 | ++ 	    lsif_configuration_policies.retention_duration_hours,  | 
 | 60 | ++ 	    lsif_configuration_policies.retain_intermediate_commits,  | 
 | 61 | ++ 	    lsif_configuration_policies.indexing_enabled,  | 
 | 62 | ++ 	    lsif_configuration_policies.index_commit_max_age_hours,  | 
 | 63 | ++ 	    lsif_configuration_policies.index_intermediate_commits,  | 
 | 64 | ++ 	    lsif_configuration_policies.protected,  | 
 | 65 | ++ 	    lsif_configuration_policies.repository_patterns,  | 
 | 66 | ++ 	    lsif_configuration_policies.last_resolved_at,  | 
 | 67 | ++ 	    lsif_configuration_policies.embeddings_enabled  | 
 | 68 | +  	   FROM lsif_configuration_policies;  | 
 | 69 | +  	"""  | 
 | 70 | +  )  | 
 | 71 | + | 
 | 72 | +codeintel_configuration_policies_repository_pattern_lookup:  | 
 | 73 | +Problem: Unexpected definition of view "codeintel_configuration_policies_repository_pattern_lookup"  | 
 | 74 | +Solution: redefine the view  | 
 | 75 | +Diff:  | 
 | 76 | +  (  | 
 | 77 | +  	"""  | 
 | 78 | +- 	 SELECT policy_id,  | 
 | 79 | +- 	    repo_id  | 
 | 80 | ++ 	 SELECT lsif_configuration_policies_repository_pattern_lookup.policy_id,  | 
 | 81 | ++ 	    lsif_configuration_policies_repository_pattern_lookup.repo_id  | 
 | 82 | +  	   FROM lsif_configuration_policies_repository_pattern_lookup;  | 
 | 83 | +  	"""  | 
 | 84 | +  )  | 
 | 85 | + | 
 | 86 | +lsif_dumps:  | 
 | 87 | +Problem: Unexpected definition of view "lsif_dumps"  | 
 | 88 | +Solution: redefine the view  | 
 | 89 | +Diff:  | 
 | 90 | +  strings.Join({  | 
 | 91 | +  	" SELECT ",  | 
 | 92 | ++ 	"u.",  | 
 | 93 | +  	"id,\n    ",  | 
 | 94 | ++ 	"u.",  | 
 | 95 | +  	"commit,\n    ",  | 
 | 96 | +- 	"root,\n    queued_at,\n    uploaded_at,\n    state,\n    ",  | 
 | 97 | ++ 	"u.root,\n    u.queued_at,\n    u.uploaded_at,\n    u.state,\n    u.",  | 
 | 98 | +  	"failure_message,\n    ",  | 
 | 99 | ++ 	"u.",  | 
 | 100 | +  	"started_at,\n    ",  | 
 | 101 | ++ 	"u.",  | 
 | 102 | +  	"finished_at,\n    ",  | 
 | 103 | ++ 	"u.",  | 
 | 104 | +  	"repository_id,\n    ",  | 
 | 105 | ++ 	"u.",  | 
 | 106 | +  	"indexer,\n    ",  | 
 | 107 | ++ 	"u.",  | 
 | 108 | +  	"indexer_version,\n    ",  | 
 | 109 | ++ 	"u.",  | 
 | 110 | +  	"num_parts,\n    ",  | 
 | 111 | ++ 	"u.",  | 
 | 112 | +  	"uploaded_parts,\n    ",  | 
 | 113 | ++ 	"u.",  | 
 | 114 | +  	"process_after,\n    ",  | 
 | 115 | ++ 	"u.",  | 
 | 116 | +  	"num_resets,\n    ",  | 
 | 117 | ++ 	"u.",  | 
 | 118 | +  	"upload_size,\n    ",  | 
 | 119 | ++ 	"u.",  | 
 | 120 | +  	"num_failures,\n    ",  | 
 | 121 | ++ 	"u.",  | 
 | 122 | +  	"associated_index_id,\n    ",  | 
 | 123 | ++ 	"u.",  | 
 | 124 | +  	"expired,\n    ",  | 
 | 125 | ++ 	"u.",  | 
 | 126 | +  	"last_retention_scan_at,\n    ",  | 
 | 127 | ++ 	"u.",  | 
 | 128 | +  	"finished_at AS processed_at\n   FROM lsif_uploads u\n  WHERE ((",  | 
 | 129 | ++ 	"u.",  | 
 | 130 | +  	"state = 'completed'::text) OR (",  | 
 | 131 | ++ 	"u.",  | 
 | 132 | +  	"state = 'deleting'::text));",  | 
 | 133 | +  }, "")  | 
 | 134 | + | 
 | 135 | +outbound_webhooks_with_event_types:  | 
 | 136 | +Problem: Unexpected definition of view "outbound_webhooks_with_event_types"  | 
 | 137 | +Solution: redefine the view  | 
 | 138 | +Diff:  | 
 | 139 | +  (  | 
 | 140 | +  	"""  | 
 | 141 | +- 	 SELECT id,  | 
 | 142 | +- 	    created_by,  | 
 | 143 | +- 	    created_at,  | 
 | 144 | +- 	    updated_by,  | 
 | 145 | +- 	    updated_at,  | 
 | 146 | +- 	    encryption_key_id,  | 
 | 147 | +- 	    url,  | 
 | 148 | +- 	    secret,  | 
 | 149 | ++ 	 SELECT outbound_webhooks.id,  | 
 | 150 | ++ 	    outbound_webhooks.created_by,  | 
 | 151 | ++ 	    outbound_webhooks.created_at,  | 
 | 152 | ++ 	    outbound_webhooks.updated_by,  | 
 | 153 | ++ 	    outbound_webhooks.updated_at,  | 
 | 154 | ++ 	    outbound_webhooks.encryption_key_id,  | 
 | 155 | ++ 	    outbound_webhooks.url,  | 
 | 156 | ++ 	    outbound_webhooks.secret,  | 
 | 157 | +  	    array_to_json(ARRAY( SELECT json_build_object('id', outbound_webhook_event_types.id, 'outbound_webhook_id', outbound_webhook_event_types.outbound_webhook_id, 'event_type', outbound_webhook_event_types.event_type, 'scope', outbound_webhook_event_types.scope) AS json_build_object  | 
 | 158 | +  	           FROM outbound_webhook_event_types  | 
 | 159 | +  	... // 2 identical lines  | 
 | 160 | +  	"""  | 
 | 161 | +  )  | 
 | 162 | + | 
 | 163 | +site_config:  | 
 | 164 | +Problem: Unexpected definition of view "site_config"  | 
 | 165 | +Solution: redefine the view  | 
 | 166 | +Diff:  | 
 | 167 | +  (  | 
 | 168 | +  	"""  | 
 | 169 | +- 	 SELECT site_id,  | 
 | 170 | +- 	    initialized  | 
 | 171 | ++ 	 SELECT global_state.site_id,  | 
 | 172 | ++ 	    global_state.initialized  | 
 | 173 | +  	   FROM global_state;  | 
 | 174 | +  	"""  | 
 | 175 | +  )  | 
 | 176 | +```  | 
 | 177 | + | 
 | 178 | +## Solutions for Handling Schema Drift  | 
 | 179 | + | 
 | 180 | +If you're confident that your instance is seeing database drift associated with the PG12 to PG16 upgrade, you can run a nultiversion upgrade via migrator `upgrade` or run `autoupgrade` using the following options.  | 
 | 181 | + | 
 | 182 | +To run `autoupgrade` via the frontend, set the `SRC_AUTOUPGRADE_IGNORE_DRIFT=true` environment variable in the frontend container.  | 
 | 183 | + | 
 | 184 | +To run migrators `upgrade` command add the `--skip-drift-check` flag to migrator's entrycommand as below:  | 
 | 185 | +```yaml  | 
 | 186 | +command: ['upgrade', '-from', '5.5.0', '-to', '5.10.0', '--skip-drift-check=true']               | 
 | 187 | +```  | 
 | 188 | +
  | 
 | 189 | +If you have any concerns about the drift, please reach out to us at [email protected]  | 
0 commit comments