We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
 Column API should support creating columns without names 
## Problem
The `name` parameter for the column API shouldn't be required.

## Proposed solution
We should auto-generate a name if it was not specified.

## Additional context
Similar to #449. Please follow a similar naming scheme of `Column n`.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mathesar/api/serializers/columns.py`
Content:
```
1 from rest_framework import serializers
2 from rest_framework.exceptions import ValidationError
3 from rest_framework.fields import empty
4 from rest_framework.settings import api_settings
5 
6 from mathesar.api.exceptions.mixins import MathesarErrorMessageMixin
7 from mathesar.api.serializers.shared_serializers import (
8     DisplayOptionsMappingSerializer,
9     DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY,
10 )
11 from mathesar.models import Column
12 
13 
14 class InputValueField(serializers.CharField):
15     """
16     Takes in an arbitrary value. Emulates the record creation endpoint,
17     which takes in arbitrary values (un-validated and un-processed request.data).
18     This field replicates that behavior in a serializer.
19     """
20 
21     def to_internal_value(self, data):
22         return data
23 
24     def to_representation(self, value):
25         return value
26 
27 
28 class TypeOptionSerializer(MathesarErrorMessageMixin, serializers.Serializer):
29     length = serializers.IntegerField(required=False)
30     precision = serializers.IntegerField(required=False)
31     scale = serializers.IntegerField(required=False)
32     fields = serializers.CharField(required=False)
33 
34     def run_validation(self, data=empty):
35         # Ensure that there are no unknown type options passed in.
36         if data is not empty:
37             unknown = set(data) - set(self.fields)
38             if unknown:
39                 errors = ['Unknown field: {}'.format(field) for field in unknown]
40                 raise serializers.ValidationError({
41                     api_settings.NON_FIELD_ERRORS_KEY: errors,
42                 })
43 
44         return super(TypeOptionSerializer, self).run_validation(data)
45 
46 
47 class SimpleColumnSerializer(MathesarErrorMessageMixin, serializers.ModelSerializer):
48     class Meta:
49         model = Column
50         fields = ('id',
51                   'name',
52                   'type',
53                   'type_options',
54                   'display_options'
55                   )
56     name = serializers.CharField()
57     type = serializers.CharField(source='plain_type')
58     type_options = TypeOptionSerializer(required=False, allow_null=True)
59     display_options = DisplayOptionsMappingSerializer(required=False, allow_null=True)
60 
61     def to_representation(self, instance):
62         if isinstance(instance, dict):
63             instance_type = instance.get('type')
64         else:
65             instance_type = instance.plain_type
66         self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY] = str(instance_type)
67         return super().to_representation(instance)
68 
69     def to_internal_value(self, data):
70         if self.partial and 'type' not in data:
71             instance_type = getattr(self.instance, 'plain_type', None)
72             if instance_type is not None:
73                 self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY] = str(instance_type)
74         else:
75             self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY] = data.get('type', None)
76         return super().to_internal_value(data)
77 
78 
79 class ColumnDefaultSerializer(MathesarErrorMessageMixin, serializers.Serializer):
80     value = InputValueField()
81     is_dynamic = serializers.BooleanField(read_only=True)
82 
83 
84 class ColumnSerializer(SimpleColumnSerializer):
85     class Meta(SimpleColumnSerializer.Meta):
86         fields = SimpleColumnSerializer.Meta.fields + (
87             'nullable',
88             'primary_key',
89             'source_column',
90             'copy_source_data',
91             'copy_source_constraints',
92             'index',
93             'valid_target_types',
94             'default'
95         )
96         model_fields = ('display_options',)
97 
98     name = serializers.CharField(required=False)
99 
100     # From scratch fields
101     type = serializers.CharField(source='plain_type', required=False)
102     nullable = serializers.BooleanField(default=True)
103     primary_key = serializers.BooleanField(default=False)
104     default = ColumnDefaultSerializer(
105         source='column_default_dict', required=False, allow_null=True, default=None
106     )
107 
108     # From duplication fields
109     source_column = serializers.PrimaryKeyRelatedField(queryset=Column.current_objects.all(), required=False, write_only=True)
110     copy_source_data = serializers.BooleanField(default=True, write_only=True)
111     copy_source_constraints = serializers.BooleanField(default=True, write_only=True)
112 
113     # Read only fields
114     index = serializers.IntegerField(source='column_index', read_only=True)
115     valid_target_types = serializers.ListField(read_only=True)
116 
117     def validate(self, data):
118         if not self.partial:
119             from_scratch_required_fields = ['name', 'type']
120             from_scratch_specific_fields = ['type', 'nullable', 'primary_key']
121             from_dupe_required_fields = ['source_column']
122             from_dupe_specific_fields = ['source_column', 'copy_source_data',
123                                          'copy_source_constraints']
124 
125             # Note that we run validation on self.initial_data, as `data` has defaults
126             # filled in for fields that weren't specified by the request
127             from_scratch_required_all = all([
128                 f in self.initial_data for f in from_scratch_required_fields
129             ])
130             from_scratch_specific_in = [
131                 f for f in from_scratch_specific_fields if f in self.initial_data
132             ]
133             from_dupe_required_all = all([
134                 f in self.initial_data for f in from_dupe_required_fields
135             ])
136             from_dupe_specific_in = [
137                 f for f in from_dupe_specific_fields if f in self.initial_data
138             ]
139 
140             if len(from_dupe_specific_in) and len(from_scratch_specific_in):
141                 raise ValidationError(
142                     f'{from_scratch_specific_in} cannot be passed in if '
143                     f'{from_dupe_specific_in} has also been passed in.'
144                 )
145             elif not from_dupe_required_all and not from_scratch_required_all:
146                 # We default to from scratch required fields if no fields are passed
147                 if len(from_dupe_specific_in) and not len(from_scratch_specific_in):
148                     required_fields = from_dupe_required_fields
149                 else:
150                     required_fields = from_scratch_required_fields
151                 raise ValidationError({
152                     f: ['This field is required.']
153                     for f in required_fields
154                     if f not in self.initial_data
155                 })
156         return data
157 
158     @property
159     def validated_model_fields(self):
160         return {key: self.validated_data[key] for key in self.validated_data if key in self.Meta.model_fields}
161
```

Path: `db/columns/operations/create.py`
Content:
```
1 from alembic.migration import MigrationContext
2 from alembic.operations import Operations
3 from sqlalchemy.ext import compiler
4 from sqlalchemy.exc import DataError
5 from sqlalchemy.schema import DDLElement
6 from psycopg2.errors import InvalidTextRepresentation, InvalidParameterValue
7 
8 from db.columns.base import MathesarColumn
9 from db.columns.defaults import DEFAULT, NAME, NULLABLE, TYPE
10 from db.columns.exceptions import InvalidDefaultError, InvalidTypeError, InvalidTypeOptionError
11 from db.columns.operations.alter import set_column_default, change_column_nullable
12 from db.columns.operations.select import (
13     get_column_attnum_from_name, get_column_default, get_column_name_from_attnum,
14 )
15 from db.columns.utils import get_mathesar_column_with_engine
16 from db.constraints.operations.create import copy_constraint
17 from db.constraints.operations.select import get_column_constraints
18 from db.constraints import utils as constraint_utils
19 from db.tables.operations.select import reflect_table_from_oid
20 from db.types.operations.cast import get_supported_alter_column_types
21 
22 
23 def create_column(engine, table_oid, column_data):
24     column_type = column_data.get(TYPE, column_data.get("type"))
25     column_type_options = column_data.get("type_options", {})
26     column_nullable = column_data.get(NULLABLE, True)
27     default_value = column_data.get(DEFAULT, {}).get('value')
28     prepared_default_value = str(default_value) if default_value is not None else None
29     supported_types = get_supported_alter_column_types(
30         engine, friendly_names=False,
31     )
32     sa_type = supported_types.get(column_type)
33     if sa_type is None:
34         # Requested type not supported. falling back to VARCHAR
35         sa_type = supported_types["VARCHAR"]
36         column_type_options = {}
37     table = reflect_table_from_oid(table_oid, engine)
38 
39     try:
40         column = MathesarColumn(
41             column_data[NAME], sa_type(**column_type_options), nullable=column_nullable,
42             server_default=prepared_default_value,
43         )
44     except DataError as e:
45         if type(e.orig) == InvalidTextRepresentation:
46             raise InvalidTypeError
47         else:
48             raise e
49 
50     table = reflect_table_from_oid(table_oid, engine)
51     try:
52         with engine.begin() as conn:
53             ctx = MigrationContext.configure(conn)
54             op = Operations(ctx)
55             op.add_column(table.name, column, schema=table.schema)
56     except DataError as e:
57         if type(e.orig) == InvalidTextRepresentation:
58             raise InvalidDefaultError
59         elif type(e.orig) == InvalidParameterValue:
60             raise InvalidTypeOptionError
61         else:
62             raise e
63 
64     return get_mathesar_column_with_engine(
65         reflect_table_from_oid(table_oid, engine).columns[column_data[NAME]],
66         engine
67     )
68 
69 
70 def _gen_col_name(table, column_name):
71     num = 1
72     new_column_name = f"{column_name}_{num}"
73     while new_column_name in table.c:
74         num += 1
75         new_column_name = f"{column_name}_{num}"
76     return new_column_name
77 
78 
79 class CopyColumn(DDLElement):
80     def __init__(self, schema, table, to_column, from_column):
81         self.schema = schema
82         self.table = table
83         self.to_column = to_column
84         self.from_column = from_column
85 
86 
87 @compiler.compiles(CopyColumn, "postgresql")
88 def compile_copy_column(element, compiler, **_):
89     return 'UPDATE "%s"."%s" SET "%s" = "%s"' % (
90         element.schema,
91         element.table,
92         element.to_column,
93         element.from_column
94     )
95 
96 
97 def _duplicate_column_data(table_oid, from_column_attnum, to_column_attnum, engine):
98     table = reflect_table_from_oid(table_oid, engine)
99     from_column_name = get_column_name_from_attnum(table_oid, from_column_attnum, engine)
100     to_column_name = get_column_name_from_attnum(table_oid, to_column_attnum, engine)
101     copy = CopyColumn(
102         table.schema,
103         table.name,
104         to_column_name,
105         from_column_name,
106     )
107     with engine.begin() as conn:
108         conn.execute(copy)
109     from_default = get_column_default(table_oid, from_column_attnum, engine)
110     if from_default is not None:
111         with engine.begin() as conn:
112             set_column_default(table_oid, to_column_attnum, engine, conn, from_default)
113 
114 
115 def _duplicate_column_constraints(table_oid, from_column_attnum, to_column_attnum, engine, copy_nullable=True):
116     table = reflect_table_from_oid(table_oid, engine)
117     from_column_name = get_column_name_from_attnum(table_oid, from_column_attnum, engine)
118     if copy_nullable:
119         with engine.begin() as conn:
120             change_column_nullable(table_oid, to_column_attnum, engine, conn, table.c[from_column_name].nullable)
121     constraints = get_column_constraints(from_column_attnum, table_oid, engine)
122     for constraint in constraints:
123         constraint_type = constraint_utils.get_constraint_type_from_char(constraint.contype)
124         if constraint_type != constraint_utils.ConstraintType.UNIQUE.value:
125             # Don't allow duplication of primary keys
126             continue
127         copy_constraint(
128             table_oid, engine, constraint, from_column_attnum, to_column_attnum
129         )
130 
131 
132 def duplicate_column(table_oid, copy_from_attnum, engine, new_column_name=None, copy_data=True, copy_constraints=True):
133     table = reflect_table_from_oid(table_oid, engine)
134     copy_from_name = get_column_name_from_attnum(table_oid, copy_from_attnum, engine)
135     from_column = table.c[copy_from_name]
136     if new_column_name is None:
137         new_column_name = _gen_col_name(table, from_column.name)
138 
139     column_data = {
140         NAME: new_column_name,
141         "type": from_column.type.compile(dialect=engine.dialect),
142         NULLABLE: True,
143     }
144     new_column = create_column(engine, table_oid, column_data)
145     new_column_attnum = get_column_attnum_from_name(table_oid, new_column.name, engine)
146     if copy_data:
147         _duplicate_column_data(
148             table_oid,
149             copy_from_attnum,
150             new_column_attnum,
151             engine
152         )
153 
154     if copy_constraints:
155         _duplicate_column_constraints(
156             table_oid,
157             copy_from_attnum,
158             new_column_attnum,
159             engine,
160             copy_nullable=copy_data
161         )
162 
163     table = reflect_table_from_oid(table_oid, engine)
164     column_name = get_column_name_from_attnum(table_oid, new_column_attnum, engine)
165     return get_mathesar_column_with_engine(table.c[column_name], engine)
166
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/db/columns/operations/create.py b/db/columns/operations/create.py
--- a/db/columns/operations/create.py
+++ b/db/columns/operations/create.py
@@ -19,8 +19,14 @@
 from db.tables.operations.select import reflect_table_from_oid
 from db.types.operations.cast import get_supported_alter_column_types
 
+COLUMN_NAME_TEMPLATE = 'Column'
+
 
 def create_column(engine, table_oid, column_data):
+    table = reflect_table_from_oid(table_oid, engine)
+    column_name = column_data.get(NAME, '').strip()
+    if column_name == '':
+        column_data[NAME] = gen_col_name(table)
     column_type = column_data.get(TYPE, column_data.get("type"))
     column_type_options = column_data.get("type_options", {})
     column_nullable = column_data.get(NULLABLE, True)
@@ -67,6 +73,13 @@
     )
 
 
+def gen_col_name(table):
+    base_name = COLUMN_NAME_TEMPLATE
+    col_num = len(table.c)
+    name = f'{base_name} {col_num}'
+    return name
+
+
 def _gen_col_name(table, column_name):
     num = 1
     new_column_name = f"{column_name}_{num}"
diff --git a/mathesar/api/serializers/columns.py b/mathesar/api/serializers/columns.py
--- a/mathesar/api/serializers/columns.py
+++ b/mathesar/api/serializers/columns.py
@@ -95,7 +95,7 @@
         )
         model_fields = ('display_options',)
 
-    name = serializers.CharField(required=False)
+    name = serializers.CharField(required=False, allow_blank=True)
 
     # From scratch fields
     type = serializers.CharField(source='plain_type', required=False)
@@ -116,7 +116,7 @@
 
     def validate(self, data):
         if not self.partial:
-            from_scratch_required_fields = ['name', 'type']
+            from_scratch_required_fields = ['type']
             from_scratch_specific_fields = ['type', 'nullable', 'primary_key']
             from_dupe_required_fields = ['source_column']
             from_dupe_specific_fields = ['source_column', 'copy_source_data',

{"golden_diff": "diff --git a/db/columns/operations/create.py b/db/columns/operations/create.py\n--- a/db/columns/operations/create.py\n+++ b/db/columns/operations/create.py\n@@ -19,8 +19,14 @@\n from db.tables.operations.select import reflect_table_from_oid\n from db.types.operations.cast import get_supported_alter_column_types\n \n+COLUMN_NAME_TEMPLATE = 'Column'\n+\n \n def create_column(engine, table_oid, column_data):\n+    table = reflect_table_from_oid(table_oid, engine)\n+    column_name = column_data.get(NAME, '').strip()\n+    if column_name == '':\n+        column_data[NAME] = gen_col_name(table)\n     column_type = column_data.get(TYPE, column_data.get(\"type\"))\n     column_type_options = column_data.get(\"type_options\", {})\n     column_nullable = column_data.get(NULLABLE, True)\n@@ -67,6 +73,13 @@\n     )\n \n \n+def gen_col_name(table):\n+    base_name = COLUMN_NAME_TEMPLATE\n+    col_num = len(table.c)\n+    name = f'{base_name} {col_num}'\n+    return name\n+\n+\n def _gen_col_name(table, column_name):\n     num = 1\n     new_column_name = f\"{column_name}_{num}\"\ndiff --git a/mathesar/api/serializers/columns.py b/mathesar/api/serializers/columns.py\n--- a/mathesar/api/serializers/columns.py\n+++ b/mathesar/api/serializers/columns.py\n@@ -95,7 +95,7 @@\n         )\n         model_fields = ('display_options',)\n \n-    name = serializers.CharField(required=False)\n+    name = serializers.CharField(required=False, allow_blank=True)\n \n     # From scratch fields\n     type = serializers.CharField(source='plain_type', required=False)\n@@ -116,7 +116,7 @@\n \n     def validate(self, data):\n         if not self.partial:\n-            from_scratch_required_fields = ['name', 'type']\n+            from_scratch_required_fields = ['type']\n             from_scratch_specific_fields = ['type', 'nullable', 'primary_key']\n             from_dupe_required_fields = ['source_column']\n             from_dupe_specific_fields = ['source_column', 'copy_source_data',\n", "issue": " Column API should support creating columns without names \n## Problem\r\nThe `name` parameter for the column API shouldn't be required.\r\n\r\n## Proposed solution\r\nWe should auto-generate a name if it was not specified.\r\n\r\n## Additional context\r\nSimilar to #449. Please follow a similar naming scheme of `Column n`.\r\n\n", "before_files": [{"content": "from rest_framework import serializers\nfrom rest_framework.exceptions import ValidationError\nfrom rest_framework.fields import empty\nfrom rest_framework.settings import api_settings\n\nfrom mathesar.api.exceptions.mixins import MathesarErrorMessageMixin\nfrom mathesar.api.serializers.shared_serializers import (\n    DisplayOptionsMappingSerializer,\n    DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY,\n)\nfrom mathesar.models import Column\n\n\nclass InputValueField(serializers.CharField):\n    \"\"\"\n    Takes in an arbitrary value. Emulates the record creation endpoint,\n    which takes in arbitrary values (un-validated and un-processed request.data).\n    This field replicates that behavior in a serializer.\n    \"\"\"\n\n    def to_internal_value(self, data):\n        return data\n\n    def to_representation(self, value):\n        return value\n\n\nclass TypeOptionSerializer(MathesarErrorMessageMixin, serializers.Serializer):\n    length = serializers.IntegerField(required=False)\n    precision = serializers.IntegerField(required=False)\n    scale = serializers.IntegerField(required=False)\n    fields = serializers.CharField(required=False)\n\n    def run_validation(self, data=empty):\n        # Ensure that there are no unknown type options passed in.\n        if data is not empty:\n            unknown = set(data) - set(self.fields)\n            if unknown:\n                errors = ['Unknown field: {}'.format(field) for field in unknown]\n                raise serializers.ValidationError({\n                    api_settings.NON_FIELD_ERRORS_KEY: errors,\n                })\n\n        return super(TypeOptionSerializer, self).run_validation(data)\n\n\nclass SimpleColumnSerializer(MathesarErrorMessageMixin, serializers.ModelSerializer):\n    class Meta:\n        model = Column\n        fields = ('id',\n                  'name',\n                  'type',\n                  'type_options',\n                  'display_options'\n                  )\n    name = serializers.CharField()\n    type = serializers.CharField(source='plain_type')\n    type_options = TypeOptionSerializer(required=False, allow_null=True)\n    display_options = DisplayOptionsMappingSerializer(required=False, allow_null=True)\n\n    def to_representation(self, instance):\n        if isinstance(instance, dict):\n            instance_type = instance.get('type')\n        else:\n            instance_type = instance.plain_type\n        self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY] = str(instance_type)\n        return super().to_representation(instance)\n\n    def to_internal_value(self, data):\n        if self.partial and 'type' not in data:\n            instance_type = getattr(self.instance, 'plain_type', None)\n            if instance_type is not None:\n                self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY] = str(instance_type)\n        else:\n            self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY] = data.get('type', None)\n        return super().to_internal_value(data)\n\n\nclass ColumnDefaultSerializer(MathesarErrorMessageMixin, serializers.Serializer):\n    value = InputValueField()\n    is_dynamic = serializers.BooleanField(read_only=True)\n\n\nclass ColumnSerializer(SimpleColumnSerializer):\n    class Meta(SimpleColumnSerializer.Meta):\n        fields = SimpleColumnSerializer.Meta.fields + (\n            'nullable',\n            'primary_key',\n            'source_column',\n            'copy_source_data',\n            'copy_source_constraints',\n            'index',\n            'valid_target_types',\n            'default'\n        )\n        model_fields = ('display_options',)\n\n    name = serializers.CharField(required=False)\n\n    # From scratch fields\n    type = serializers.CharField(source='plain_type', required=False)\n    nullable = serializers.BooleanField(default=True)\n    primary_key = serializers.BooleanField(default=False)\n    default = ColumnDefaultSerializer(\n        source='column_default_dict', required=False, allow_null=True, default=None\n    )\n\n    # From duplication fields\n    source_column = serializers.PrimaryKeyRelatedField(queryset=Column.current_objects.all(), required=False, write_only=True)\n    copy_source_data = serializers.BooleanField(default=True, write_only=True)\n    copy_source_constraints = serializers.BooleanField(default=True, write_only=True)\n\n    # Read only fields\n    index = serializers.IntegerField(source='column_index', read_only=True)\n    valid_target_types = serializers.ListField(read_only=True)\n\n    def validate(self, data):\n        if not self.partial:\n            from_scratch_required_fields = ['name', 'type']\n            from_scratch_specific_fields = ['type', 'nullable', 'primary_key']\n            from_dupe_required_fields = ['source_column']\n            from_dupe_specific_fields = ['source_column', 'copy_source_data',\n                                         'copy_source_constraints']\n\n            # Note that we run validation on self.initial_data, as `data` has defaults\n            # filled in for fields that weren't specified by the request\n            from_scratch_required_all = all([\n                f in self.initial_data for f in from_scratch_required_fields\n            ])\n            from_scratch_specific_in = [\n                f for f in from_scratch_specific_fields if f in self.initial_data\n            ]\n            from_dupe_required_all = all([\n                f in self.initial_data for f in from_dupe_required_fields\n            ])\n            from_dupe_specific_in = [\n                f for f in from_dupe_specific_fields if f in self.initial_data\n            ]\n\n            if len(from_dupe_specific_in) and len(from_scratch_specific_in):\n                raise ValidationError(\n                    f'{from_scratch_specific_in} cannot be passed in if '\n                    f'{from_dupe_specific_in} has also been passed in.'\n                )\n            elif not from_dupe_required_all and not from_scratch_required_all:\n                # We default to from scratch required fields if no fields are passed\n                if len(from_dupe_specific_in) and not len(from_scratch_specific_in):\n                    required_fields = from_dupe_required_fields\n                else:\n                    required_fields = from_scratch_required_fields\n                raise ValidationError({\n                    f: ['This field is required.']\n                    for f in required_fields\n                    if f not in self.initial_data\n                })\n        return data\n\n    @property\n    def validated_model_fields(self):\n        return {key: self.validated_data[key] for key in self.validated_data if key in self.Meta.model_fields}\n", "path": "mathesar/api/serializers/columns.py"}, {"content": "from alembic.migration import MigrationContext\nfrom alembic.operations import Operations\nfrom sqlalchemy.ext import compiler\nfrom sqlalchemy.exc import DataError\nfrom sqlalchemy.schema import DDLElement\nfrom psycopg2.errors import InvalidTextRepresentation, InvalidParameterValue\n\nfrom db.columns.base import MathesarColumn\nfrom db.columns.defaults import DEFAULT, NAME, NULLABLE, TYPE\nfrom db.columns.exceptions import InvalidDefaultError, InvalidTypeError, InvalidTypeOptionError\nfrom db.columns.operations.alter import set_column_default, change_column_nullable\nfrom db.columns.operations.select import (\n    get_column_attnum_from_name, get_column_default, get_column_name_from_attnum,\n)\nfrom db.columns.utils import get_mathesar_column_with_engine\nfrom db.constraints.operations.create import copy_constraint\nfrom db.constraints.operations.select import get_column_constraints\nfrom db.constraints import utils as constraint_utils\nfrom db.tables.operations.select import reflect_table_from_oid\nfrom db.types.operations.cast import get_supported_alter_column_types\n\n\ndef create_column(engine, table_oid, column_data):\n    column_type = column_data.get(TYPE, column_data.get(\"type\"))\n    column_type_options = column_data.get(\"type_options\", {})\n    column_nullable = column_data.get(NULLABLE, True)\n    default_value = column_data.get(DEFAULT, {}).get('value')\n    prepared_default_value = str(default_value) if default_value is not None else None\n    supported_types = get_supported_alter_column_types(\n        engine, friendly_names=False,\n    )\n    sa_type = supported_types.get(column_type)\n    if sa_type is None:\n        # Requested type not supported. falling back to VARCHAR\n        sa_type = supported_types[\"VARCHAR\"]\n        column_type_options = {}\n    table = reflect_table_from_oid(table_oid, engine)\n\n    try:\n        column = MathesarColumn(\n            column_data[NAME], sa_type(**column_type_options), nullable=column_nullable,\n            server_default=prepared_default_value,\n        )\n    except DataError as e:\n        if type(e.orig) == InvalidTextRepresentation:\n            raise InvalidTypeError\n        else:\n            raise e\n\n    table = reflect_table_from_oid(table_oid, engine)\n    try:\n        with engine.begin() as conn:\n            ctx = MigrationContext.configure(conn)\n            op = Operations(ctx)\n            op.add_column(table.name, column, schema=table.schema)\n    except DataError as e:\n        if type(e.orig) == InvalidTextRepresentation:\n            raise InvalidDefaultError\n        elif type(e.orig) == InvalidParameterValue:\n            raise InvalidTypeOptionError\n        else:\n            raise e\n\n    return get_mathesar_column_with_engine(\n        reflect_table_from_oid(table_oid, engine).columns[column_data[NAME]],\n        engine\n    )\n\n\ndef _gen_col_name(table, column_name):\n    num = 1\n    new_column_name = f\"{column_name}_{num}\"\n    while new_column_name in table.c:\n        num += 1\n        new_column_name = f\"{column_name}_{num}\"\n    return new_column_name\n\n\nclass CopyColumn(DDLElement):\n    def __init__(self, schema, table, to_column, from_column):\n        self.schema = schema\n        self.table = table\n        self.to_column = to_column\n        self.from_column = from_column\n\n\n@compiler.compiles(CopyColumn, \"postgresql\")\ndef compile_copy_column(element, compiler, **_):\n    return 'UPDATE \"%s\".\"%s\" SET \"%s\" = \"%s\"' % (\n        element.schema,\n        element.table,\n        element.to_column,\n        element.from_column\n    )\n\n\ndef _duplicate_column_data(table_oid, from_column_attnum, to_column_attnum, engine):\n    table = reflect_table_from_oid(table_oid, engine)\n    from_column_name = get_column_name_from_attnum(table_oid, from_column_attnum, engine)\n    to_column_name = get_column_name_from_attnum(table_oid, to_column_attnum, engine)\n    copy = CopyColumn(\n        table.schema,\n        table.name,\n        to_column_name,\n        from_column_name,\n    )\n    with engine.begin() as conn:\n        conn.execute(copy)\n    from_default = get_column_default(table_oid, from_column_attnum, engine)\n    if from_default is not None:\n        with engine.begin() as conn:\n            set_column_default(table_oid, to_column_attnum, engine, conn, from_default)\n\n\ndef _duplicate_column_constraints(table_oid, from_column_attnum, to_column_attnum, engine, copy_nullable=True):\n    table = reflect_table_from_oid(table_oid, engine)\n    from_column_name = get_column_name_from_attnum(table_oid, from_column_attnum, engine)\n    if copy_nullable:\n        with engine.begin() as conn:\n            change_column_nullable(table_oid, to_column_attnum, engine, conn, table.c[from_column_name].nullable)\n    constraints = get_column_constraints(from_column_attnum, table_oid, engine)\n    for constraint in constraints:\n        constraint_type = constraint_utils.get_constraint_type_from_char(constraint.contype)\n        if constraint_type != constraint_utils.ConstraintType.UNIQUE.value:\n            # Don't allow duplication of primary keys\n            continue\n        copy_constraint(\n            table_oid, engine, constraint, from_column_attnum, to_column_attnum\n        )\n\n\ndef duplicate_column(table_oid, copy_from_attnum, engine, new_column_name=None, copy_data=True, copy_constraints=True):\n    table = reflect_table_from_oid(table_oid, engine)\n    copy_from_name = get_column_name_from_attnum(table_oid, copy_from_attnum, engine)\n    from_column = table.c[copy_from_name]\n    if new_column_name is None:\n        new_column_name = _gen_col_name(table, from_column.name)\n\n    column_data = {\n        NAME: new_column_name,\n        \"type\": from_column.type.compile(dialect=engine.dialect),\n        NULLABLE: True,\n    }\n    new_column = create_column(engine, table_oid, column_data)\n    new_column_attnum = get_column_attnum_from_name(table_oid, new_column.name, engine)\n    if copy_data:\n        _duplicate_column_data(\n            table_oid,\n            copy_from_attnum,\n            new_column_attnum,\n            engine\n        )\n\n    if copy_constraints:\n        _duplicate_column_constraints(\n            table_oid,\n            copy_from_attnum,\n            new_column_attnum,\n            engine,\n            copy_nullable=copy_data\n        )\n\n    table = reflect_table_from_oid(table_oid, engine)\n    column_name = get_column_name_from_attnum(table_oid, new_column_attnum, engine)\n    return get_mathesar_column_with_engine(table.c[column_name], engine)\n", "path": "db/columns/operations/create.py"}], "after_files": [{"content": "from rest_framework import serializers\nfrom rest_framework.exceptions import ValidationError\nfrom rest_framework.fields import empty\nfrom rest_framework.settings import api_settings\n\nfrom mathesar.api.exceptions.mixins import MathesarErrorMessageMixin\nfrom mathesar.api.serializers.shared_serializers import (\n    DisplayOptionsMappingSerializer,\n    DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY,\n)\nfrom mathesar.models import Column\n\n\nclass InputValueField(serializers.CharField):\n    \"\"\"\n    Takes in an arbitrary value. Emulates the record creation endpoint,\n    which takes in arbitrary values (un-validated and un-processed request.data).\n    This field replicates that behavior in a serializer.\n    \"\"\"\n\n    def to_internal_value(self, data):\n        return data\n\n    def to_representation(self, value):\n        return value\n\n\nclass TypeOptionSerializer(MathesarErrorMessageMixin, serializers.Serializer):\n    length = serializers.IntegerField(required=False)\n    precision = serializers.IntegerField(required=False)\n    scale = serializers.IntegerField(required=False)\n    fields = serializers.CharField(required=False)\n\n    def run_validation(self, data=empty):\n        # Ensure that there are no unknown type options passed in.\n        if data is not empty:\n            unknown = set(data) - set(self.fields)\n            if unknown:\n                errors = ['Unknown field: {}'.format(field) for field in unknown]\n                raise serializers.ValidationError({\n                    api_settings.NON_FIELD_ERRORS_KEY: errors,\n                })\n\n        return super(TypeOptionSerializer, self).run_validation(data)\n\n\nclass SimpleColumnSerializer(MathesarErrorMessageMixin, serializers.ModelSerializer):\n    class Meta:\n        model = Column\n        fields = ('id',\n                  'name',\n                  'type',\n                  'type_options',\n                  'display_options'\n                  )\n    name = serializers.CharField()\n    type = serializers.CharField(source='plain_type')\n    type_options = TypeOptionSerializer(required=False, allow_null=True)\n    display_options = DisplayOptionsMappingSerializer(required=False, allow_null=True)\n\n    def to_representation(self, instance):\n        if isinstance(instance, dict):\n            instance_type = instance.get('type')\n        else:\n            instance_type = instance.plain_type\n        self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY] = str(instance_type)\n        return super().to_representation(instance)\n\n    def to_internal_value(self, data):\n        if self.partial and 'type' not in data:\n            instance_type = getattr(self.instance, 'plain_type', None)\n            if instance_type is not None:\n                self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY] = str(instance_type)\n        else:\n            self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY] = data.get('type', None)\n        return super().to_internal_value(data)\n\n\nclass ColumnDefaultSerializer(MathesarErrorMessageMixin, serializers.Serializer):\n    value = InputValueField()\n    is_dynamic = serializers.BooleanField(read_only=True)\n\n\nclass ColumnSerializer(SimpleColumnSerializer):\n    class Meta(SimpleColumnSerializer.Meta):\n        fields = SimpleColumnSerializer.Meta.fields + (\n            'nullable',\n            'primary_key',\n            'source_column',\n            'copy_source_data',\n            'copy_source_constraints',\n            'index',\n            'valid_target_types',\n            'default'\n        )\n        model_fields = ('display_options',)\n\n    name = serializers.CharField(required=False, allow_blank=True)\n\n    # From scratch fields\n    type = serializers.CharField(source='plain_type', required=False)\n    nullable = serializers.BooleanField(default=True)\n    primary_key = serializers.BooleanField(default=False)\n    default = ColumnDefaultSerializer(\n        source='column_default_dict', required=False, allow_null=True, default=None\n    )\n\n    # From duplication fields\n    source_column = serializers.PrimaryKeyRelatedField(queryset=Column.current_objects.all(), required=False, write_only=True)\n    copy_source_data = serializers.BooleanField(default=True, write_only=True)\n    copy_source_constraints = serializers.BooleanField(default=True, write_only=True)\n\n    # Read only fields\n    index = serializers.IntegerField(source='column_index', read_only=True)\n    valid_target_types = serializers.ListField(read_only=True)\n\n    def validate(self, data):\n        if not self.partial:\n            from_scratch_required_fields = ['type']\n            from_scratch_specific_fields = ['type', 'nullable', 'primary_key']\n            from_dupe_required_fields = ['source_column']\n            from_dupe_specific_fields = ['source_column', 'copy_source_data',\n                                         'copy_source_constraints']\n\n            # Note that we run validation on self.initial_data, as `data` has defaults\n            # filled in for fields that weren't specified by the request\n            from_scratch_required_all = all([\n                f in self.initial_data for f in from_scratch_required_fields\n            ])\n            from_scratch_specific_in = [\n                f for f in from_scratch_specific_fields if f in self.initial_data\n            ]\n            from_dupe_required_all = all([\n                f in self.initial_data for f in from_dupe_required_fields\n            ])\n            from_dupe_specific_in = [\n                f for f in from_dupe_specific_fields if f in self.initial_data\n            ]\n\n            if len(from_dupe_specific_in) and len(from_scratch_specific_in):\n                raise ValidationError(\n                    f'{from_scratch_specific_in} cannot be passed in if '\n                    f'{from_dupe_specific_in} has also been passed in.'\n                )\n            elif not from_dupe_required_all and not from_scratch_required_all:\n                # We default to from scratch required fields if no fields are passed\n                if len(from_dupe_specific_in) and not len(from_scratch_specific_in):\n                    required_fields = from_dupe_required_fields\n                else:\n                    required_fields = from_scratch_required_fields\n                raise ValidationError({\n                    f: ['This field is required.']\n                    for f in required_fields\n                    if f not in self.initial_data\n                })\n        return data\n\n    @property\n    def validated_model_fields(self):\n        return {key: self.validated_data[key] for key in self.validated_data if key in self.Meta.model_fields}\n", "path": "mathesar/api/serializers/columns.py"}, {"content": "from alembic.migration import MigrationContext\nfrom alembic.operations import Operations\nfrom sqlalchemy.ext import compiler\nfrom sqlalchemy.exc import DataError\nfrom sqlalchemy.schema import DDLElement\nfrom psycopg2.errors import InvalidTextRepresentation, InvalidParameterValue\n\nfrom db.columns.base import MathesarColumn\nfrom db.columns.defaults import DEFAULT, NAME, NULLABLE, TYPE\nfrom db.columns.exceptions import InvalidDefaultError, InvalidTypeError, InvalidTypeOptionError\nfrom db.columns.operations.alter import set_column_default, change_column_nullable\nfrom db.columns.operations.select import (\n    get_column_attnum_from_name, get_column_default, get_column_name_from_attnum,\n)\nfrom db.columns.utils import get_mathesar_column_with_engine\nfrom db.constraints.operations.create import copy_constraint\nfrom db.constraints.operations.select import get_column_constraints\nfrom db.constraints import utils as constraint_utils\nfrom db.tables.operations.select import reflect_table_from_oid\nfrom db.types.operations.cast import get_supported_alter_column_types\n\nCOLUMN_NAME_TEMPLATE = 'Column'\n\n\ndef create_column(engine, table_oid, column_data):\n    table = reflect_table_from_oid(table_oid, engine)\n    column_name = column_data.get(NAME, '').strip()\n    if column_name == '':\n        column_data[NAME] = gen_col_name(table)\n    column_type = column_data.get(TYPE, column_data.get(\"type\"))\n    column_type_options = column_data.get(\"type_options\", {})\n    column_nullable = column_data.get(NULLABLE, True)\n    default_value = column_data.get(DEFAULT, {}).get('value')\n    prepared_default_value = str(default_value) if default_value is not None else None\n    supported_types = get_supported_alter_column_types(\n        engine, friendly_names=False,\n    )\n    sa_type = supported_types.get(column_type)\n    if sa_type is None:\n        # Requested type not supported. falling back to VARCHAR\n        sa_type = supported_types[\"VARCHAR\"]\n        column_type_options = {}\n    table = reflect_table_from_oid(table_oid, engine)\n\n    try:\n        column = MathesarColumn(\n            column_data[NAME], sa_type(**column_type_options), nullable=column_nullable,\n            server_default=prepared_default_value,\n        )\n    except DataError as e:\n        if type(e.orig) == InvalidTextRepresentation:\n            raise InvalidTypeError\n        else:\n            raise e\n\n    table = reflect_table_from_oid(table_oid, engine)\n    try:\n        with engine.begin() as conn:\n            ctx = MigrationContext.configure(conn)\n            op = Operations(ctx)\n            op.add_column(table.name, column, schema=table.schema)\n    except DataError as e:\n        if type(e.orig) == InvalidTextRepresentation:\n            raise InvalidDefaultError\n        elif type(e.orig) == InvalidParameterValue:\n            raise InvalidTypeOptionError\n        else:\n            raise e\n\n    return get_mathesar_column_with_engine(\n        reflect_table_from_oid(table_oid, engine).columns[column_data[NAME]],\n        engine\n    )\n\n\ndef gen_col_name(table):\n    base_name = COLUMN_NAME_TEMPLATE\n    col_num = len(table.c)\n    name = f'{base_name} {col_num}'\n    return name\n\n\ndef _gen_col_name(table, column_name):\n    num = 1\n    new_column_name = f\"{column_name}_{num}\"\n    while new_column_name in table.c:\n        num += 1\n        new_column_name = f\"{column_name}_{num}\"\n    return new_column_name\n\n\nclass CopyColumn(DDLElement):\n    def __init__(self, schema, table, to_column, from_column):\n        self.schema = schema\n        self.table = table\n        self.to_column = to_column\n        self.from_column = from_column\n\n\n@compiler.compiles(CopyColumn, \"postgresql\")\ndef compile_copy_column(element, compiler, **_):\n    return 'UPDATE \"%s\".\"%s\" SET \"%s\" = \"%s\"' % (\n        element.schema,\n        element.table,\n        element.to_column,\n        element.from_column\n    )\n\n\ndef _duplicate_column_data(table_oid, from_column_attnum, to_column_attnum, engine):\n    table = reflect_table_from_oid(table_oid, engine)\n    from_column_name = get_column_name_from_attnum(table_oid, from_column_attnum, engine)\n    to_column_name = get_column_name_from_attnum(table_oid, to_column_attnum, engine)\n    copy = CopyColumn(\n        table.schema,\n        table.name,\n        to_column_name,\n        from_column_name,\n    )\n    with engine.begin() as conn:\n        conn.execute(copy)\n    from_default = get_column_default(table_oid, from_column_attnum, engine)\n    if from_default is not None:\n        with engine.begin() as conn:\n            set_column_default(table_oid, to_column_attnum, engine, conn, from_default)\n\n\ndef _duplicate_column_constraints(table_oid, from_column_attnum, to_column_attnum, engine, copy_nullable=True):\n    table = reflect_table_from_oid(table_oid, engine)\n    from_column_name = get_column_name_from_attnum(table_oid, from_column_attnum, engine)\n    if copy_nullable:\n        with engine.begin() as conn:\n            change_column_nullable(table_oid, to_column_attnum, engine, conn, table.c[from_column_name].nullable)\n    constraints = get_column_constraints(from_column_attnum, table_oid, engine)\n    for constraint in constraints:\n        constraint_type = constraint_utils.get_constraint_type_from_char(constraint.contype)\n        if constraint_type != constraint_utils.ConstraintType.UNIQUE.value:\n            # Don't allow duplication of primary keys\n            continue\n        copy_constraint(\n            table_oid, engine, constraint, from_column_attnum, to_column_attnum\n        )\n\n\ndef duplicate_column(table_oid, copy_from_attnum, engine, new_column_name=None, copy_data=True, copy_constraints=True):\n    table = reflect_table_from_oid(table_oid, engine)\n    copy_from_name = get_column_name_from_attnum(table_oid, copy_from_attnum, engine)\n    from_column = table.c[copy_from_name]\n    if new_column_name is None:\n        new_column_name = _gen_col_name(table, from_column.name)\n\n    column_data = {\n        NAME: new_column_name,\n        \"type\": from_column.type.compile(dialect=engine.dialect),\n        NULLABLE: True,\n    }\n    new_column = create_column(engine, table_oid, column_data)\n    new_column_attnum = get_column_attnum_from_name(table_oid, new_column.name, engine)\n    if copy_data:\n        _duplicate_column_data(\n            table_oid,\n            copy_from_attnum,\n            new_column_attnum,\n            engine\n        )\n\n    if copy_constraints:\n        _duplicate_column_constraints(\n            table_oid,\n            copy_from_attnum,\n            new_column_attnum,\n            engine,\n            copy_nullable=copy_data\n        )\n\n    table = reflect_table_from_oid(table_oid, engine)\n    column_name = get_column_name_from_attnum(table_oid, new_column_attnum, engine)\n    return get_mathesar_column_with_engine(table.c[column_name], engine)\n", "path": "db/columns/operations/create.py"}]}