We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Append to PostGIS table not working when table does not exist 
@jorisvandenbossche @martinfleis 
When table does not exist in the PostGIS database, using the `if_exists="append"` raises an error because SRID check is attempted from non-existing table.

Fix is on the way. 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `geopandas/io/sql.py`
Content:
```
1 import warnings
2 
3 import pandas as pd
4 
5 import shapely.wkb
6 
7 from geopandas import GeoDataFrame
8 
9 from .. import _compat as compat
10 
11 
12 def _read_postgis(
13     sql,
14     con,
15     geom_col="geom",
16     crs=None,
17     index_col=None,
18     coerce_float=True,
19     parse_dates=None,
20     params=None,
21 ):
22     """
23     Returns a GeoDataFrame corresponding to the result of the query
24     string, which must contain a geometry column in WKB representation.
25 
26     Parameters
27     ----------
28     sql : string
29         SQL query to execute in selecting entries from database, or name
30         of the table to read from the database.
31     con : DB connection object or SQLAlchemy engine
32         Active connection to the database to query.
33     geom_col : string, default 'geom'
34         column name to convert to shapely geometries
35     crs : pyproj.CRS, optional
36         CRS to use for the returned GeoDataFrame. The value can be anything accepted
37         by :meth:`pyproj.CRS.from_user_input() <pyproj.crs.CRS.from_user_input>`,
38         such as an authority string (eg "EPSG:4326") or a WKT string.
39         If not set, tries to determine CRS from the SRID associated with the
40         first geometry in the database, and assigns that to all geometries.
41 
42     See the documentation for pandas.read_sql for further explanation
43     of the following parameters:
44     index_col, coerce_float, parse_dates, params
45 
46     Returns
47     -------
48     GeoDataFrame
49 
50     Example
51     -------
52     PostGIS
53     >>> sql = "SELECT geom, kind FROM polygons"
54     SpatiaLite
55     >>> sql = "SELECT ST_AsBinary(geom) AS geom, kind FROM polygons"
56     >>> df = geopandas.read_postgis(sql, con)
57     """
58 
59     df = pd.read_sql(
60         sql,
61         con,
62         index_col=index_col,
63         coerce_float=coerce_float,
64         parse_dates=parse_dates,
65         params=params,
66     )
67 
68     if geom_col not in df:
69         raise ValueError("Query missing geometry column '{}'".format(geom_col))
70 
71     geoms = df[geom_col].dropna()
72 
73     if not geoms.empty:
74         load_geom_bytes = shapely.wkb.loads
75         """Load from Python 3 binary."""
76 
77         def load_geom_buffer(x):
78             """Load from Python 2 binary."""
79             return shapely.wkb.loads(str(x))
80 
81         def load_geom_text(x):
82             """Load from binary encoded as text."""
83             return shapely.wkb.loads(str(x), hex=True)
84 
85         if isinstance(geoms.iat[0], bytes):
86             load_geom = load_geom_bytes
87         else:
88             load_geom = load_geom_text
89 
90         df[geom_col] = geoms = geoms.apply(load_geom)
91         if crs is None:
92             srid = shapely.geos.lgeos.GEOSGetSRID(geoms.iat[0]._geom)
93             # if no defined SRID in geodatabase, returns SRID of 0
94             if srid != 0:
95                 crs = "epsg:{}".format(srid)
96 
97     return GeoDataFrame(df, crs=crs, geometry=geom_col)
98 
99 
100 def read_postgis(*args, **kwargs):
101     import warnings
102 
103     warnings.warn(
104         "geopandas.io.sql.read_postgis() is intended for internal "
105         "use only, and will be deprecated. Use geopandas.read_postgis() instead.",
106         DeprecationWarning,
107         stacklevel=2,
108     )
109 
110     return _read_postgis(*args, **kwargs)
111 
112 
113 def _get_geometry_type(gdf):
114     """
115     Get basic geometry type of a GeoDataFrame. See more info from:
116     https://geoalchemy-2.readthedocs.io/en/latest/types.html#geoalchemy2.types._GISType
117 
118     Following rules apply:
119      - if geometries all share the same geometry-type,
120        geometries are inserted with the given GeometryType with following types:
121         - Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon,
122           GeometryCollection.
123         - LinearRing geometries will be converted into LineString -objects.
124      - in all other cases, geometries will be inserted with type GEOMETRY:
125         - a mix of Polygons and MultiPolygons in GeoSeries
126         - a mix of Points and LineStrings in GeoSeries
127         - geometry is of type GeometryCollection,
128           such as GeometryCollection([Point, LineStrings])
129      - if any of the geometries has Z-coordinate, all records will
130        be written with 3D.
131      """
132     geom_types = list(gdf.geometry.geom_type.unique())
133     has_curve = False
134 
135     for gt in geom_types:
136         if gt is None:
137             continue
138         elif "LinearRing" in gt:
139             has_curve = True
140 
141     if len(geom_types) == 1:
142         if has_curve:
143             target_geom_type = "LINESTRING"
144         else:
145             if geom_types[0] is None:
146                 raise ValueError("No valid geometries in the data.")
147             else:
148                 target_geom_type = geom_types[0].upper()
149     else:
150         target_geom_type = "GEOMETRY"
151 
152     # Check for 3D-coordinates
153     if any(gdf.geometry.has_z):
154         target_geom_type = target_geom_type + "Z"
155 
156     return target_geom_type, has_curve
157 
158 
159 def _get_srid_from_crs(gdf):
160     """
161     Get EPSG code from CRS if available. If not, return -1.
162     """
163 
164     # Use geoalchemy2 default for srid
165     # Note: undefined srid in PostGIS is 0
166     srid = -1
167     warning_msg = (
168         "Could not parse CRS from the GeoDataFrame. "
169         + "Inserting data without defined CRS.",
170     )
171     if gdf.crs is not None:
172         try:
173             srid = gdf.crs.to_epsg(min_confidence=25)
174             if srid is None:
175                 srid = -1
176                 warnings.warn(warning_msg, UserWarning, stacklevel=2)
177         except Exception:
178             warnings.warn(warning_msg, UserWarning, stacklevel=2)
179     return srid
180 
181 
182 def _convert_linearring_to_linestring(gdf, geom_name):
183     from shapely.geometry import LineString
184 
185     # Todo: Use Pygeos function once it's implemented:
186     #  https://github.com/pygeos/pygeos/issues/76
187 
188     mask = gdf.geom_type == "LinearRing"
189     gdf.loc[mask, geom_name] = gdf.loc[mask, geom_name].apply(
190         lambda geom: LineString(geom)
191     )
192     return gdf
193 
194 
195 def _convert_to_ewkb(gdf, geom_name, srid):
196     """Convert geometries to ewkb. """
197     if compat.USE_PYGEOS:
198         from pygeos import set_srid, to_wkb
199 
200         geoms = to_wkb(
201             set_srid(gdf[geom_name].values.data, srid=srid), hex=True, include_srid=True
202         )
203 
204     else:
205         from shapely.wkb import dumps
206 
207         geoms = [dumps(geom, srid=srid, hex=True) for geom in gdf[geom_name]]
208 
209     gdf[geom_name] = geoms
210     return gdf
211 
212 
213 def _psql_insert_copy(tbl, conn, keys, data_iter):
214     import io
215     import csv
216 
217     s_buf = io.StringIO()
218     writer = csv.writer(s_buf)
219     writer.writerows(data_iter)
220     s_buf.seek(0)
221 
222     columns = ", ".join('"{}"'.format(k) for k in keys)
223 
224     dbapi_conn = conn.connection
225     with dbapi_conn.cursor() as cur:
226         sql = "COPY {} ({}) FROM STDIN WITH CSV".format(tbl.table.fullname, columns)
227         cur.copy_expert(sql=sql, file=s_buf)
228 
229 
230 def _write_postgis(
231     gdf,
232     name,
233     con,
234     schema=None,
235     if_exists="fail",
236     index=False,
237     index_label=None,
238     chunksize=None,
239     dtype=None,
240 ):
241     """
242     Upload GeoDataFrame into PostGIS database.
243 
244     This method requires SQLAlchemy and GeoAlchemy2, and a PostgreSQL
245     Python driver (e.g. psycopg2) to be installed.
246 
247     Parameters
248     ----------
249     name : str
250         Name of the target table.
251     con : sqlalchemy.engine.Engine
252         Active connection to the PostGIS database.
253     if_exists : {'fail', 'replace', 'append'}, default 'fail'
254         How to behave if the table already exists:
255 
256         - fail: Raise a ValueError.
257         - replace: Drop the table before inserting new values.
258         - append: Insert new values to the existing table.
259     schema : string, optional
260         Specify the schema. If None, use default schema: 'public'.
261     index : bool, default True
262         Write DataFrame index as a column.
263         Uses *index_label* as the column name in the table.
264     index_label : string or sequence, default None
265         Column label for index column(s).
266         If None is given (default) and index is True,
267         then the index names are used.
268     chunksize : int, optional
269         Rows will be written in batches of this size at a time.
270         By default, all rows will be written at once.
271     dtype : dict of column name to SQL type, default None
272         Specifying the datatype for columns.
273         The keys should be the column names and the values
274         should be the SQLAlchemy types.
275 
276     Examples
277     --------
278 
279     >>> from sqlalchemy import create_engine
280     >>> engine = create_engine("postgres://myusername:mypassword@myhost:5432\
281 /mydatabase";)
282     >>> gdf.to_postgis("my_table", engine)
283     """
284     try:
285         from geoalchemy2 import Geometry
286     except ImportError:
287         raise ImportError("'to_postgis()' requires geoalchemy2 package. ")
288 
289     if not compat.SHAPELY_GE_17:
290         raise ImportError(
291             "'to_postgis()' requires newer version of Shapely "
292             "(>= '1.7.0').\nYou can update the library using "
293             "'pip install shapely --upgrade' or using "
294             "'conda update shapely' if using conda package manager."
295         )
296 
297     gdf = gdf.copy()
298     geom_name = gdf.geometry.name
299 
300     # Get srid
301     srid = _get_srid_from_crs(gdf)
302 
303     # Get geometry type and info whether data contains LinearRing.
304     geometry_type, has_curve = _get_geometry_type(gdf)
305 
306     # Build dtype with Geometry
307     if dtype is not None:
308         dtype[geom_name] = Geometry(geometry_type=geometry_type, srid=srid)
309     else:
310         dtype = {geom_name: Geometry(geometry_type=geometry_type, srid=srid)}
311 
312     # Convert LinearRing geometries to LineString
313     if has_curve:
314         gdf = _convert_linearring_to_linestring(gdf, geom_name)
315 
316     # Convert geometries to EWKB
317     gdf = _convert_to_ewkb(gdf, geom_name, srid)
318 
319     if if_exists == "append":
320         # Check that the geometry srid matches with the current GeoDataFrame
321         with con.begin() as connection:
322             if schema is not None:
323                 schema_name = schema
324             else:
325                 schema_name = "public"
326 
327             target_srid = connection.execute(
328                 "SELECT Find_SRID('{schema}', '{table}', '{geom_col}');".format(
329                     schema=schema_name, table=name, geom_col=geom_name
330                 )
331             ).fetchone()[0]
332 
333             if target_srid != srid:
334                 msg = (
335                     "The CRS of the target table (EPSG:{epsg_t}) differs from the "
336                     "CRS of current GeoDataFrame (EPSG:{epsg_src}).".format(
337                         epsg_t=target_srid, epsg_src=srid
338                     )
339                 )
340                 raise ValueError(msg)
341 
342     with con.begin() as connection:
343 
344         gdf.to_sql(
345             name,
346             connection,
347             schema=schema,
348             if_exists=if_exists,
349             index=index,
350             index_label=index_label,
351             chunksize=chunksize,
352             dtype=dtype,
353             method=_psql_insert_copy,
354         )
355 
356     return
357
```
--- 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/geopandas/io/sql.py b/geopandas/io/sql.py
--- a/geopandas/io/sql.py
+++ b/geopandas/io/sql.py
@@ -324,20 +324,22 @@
             else:
                 schema_name = "public"
 
-            target_srid = connection.execute(
-                "SELECT Find_SRID('{schema}', '{table}', '{geom_col}');".format(
-                    schema=schema_name, table=name, geom_col=geom_name
-                )
-            ).fetchone()[0]
-
-            if target_srid != srid:
-                msg = (
-                    "The CRS of the target table (EPSG:{epsg_t}) differs from the "
-                    "CRS of current GeoDataFrame (EPSG:{epsg_src}).".format(
-                        epsg_t=target_srid, epsg_src=srid
+            # Only check SRID if table exists
+            if connection.run_callable(connection.dialect.has_table, name, schema):
+                target_srid = connection.execute(
+                    "SELECT Find_SRID('{schema}', '{table}', '{geom_col}');".format(
+                        schema=schema_name, table=name, geom_col=geom_name
                     )
-                )
-                raise ValueError(msg)
+                ).fetchone()[0]
+
+                if target_srid != srid:
+                    msg = (
+                        "The CRS of the target table (EPSG:{epsg_t}) differs from the "
+                        "CRS of current GeoDataFrame (EPSG:{epsg_src}).".format(
+                            epsg_t=target_srid, epsg_src=srid
+                        )
+                    )
+                    raise ValueError(msg)
 
     with con.begin() as connection:

{"golden_diff": "diff --git a/geopandas/io/sql.py b/geopandas/io/sql.py\n--- a/geopandas/io/sql.py\n+++ b/geopandas/io/sql.py\n@@ -324,20 +324,22 @@\n             else:\n                 schema_name = \"public\"\n \n-            target_srid = connection.execute(\n-                \"SELECT Find_SRID('{schema}', '{table}', '{geom_col}');\".format(\n-                    schema=schema_name, table=name, geom_col=geom_name\n-                )\n-            ).fetchone()[0]\n-\n-            if target_srid != srid:\n-                msg = (\n-                    \"The CRS of the target table (EPSG:{epsg_t}) differs from the \"\n-                    \"CRS of current GeoDataFrame (EPSG:{epsg_src}).\".format(\n-                        epsg_t=target_srid, epsg_src=srid\n+            # Only check SRID if table exists\n+            if connection.run_callable(connection.dialect.has_table, name, schema):\n+                target_srid = connection.execute(\n+                    \"SELECT Find_SRID('{schema}', '{table}', '{geom_col}');\".format(\n+                        schema=schema_name, table=name, geom_col=geom_name\n                     )\n-                )\n-                raise ValueError(msg)\n+                ).fetchone()[0]\n+\n+                if target_srid != srid:\n+                    msg = (\n+                        \"The CRS of the target table (EPSG:{epsg_t}) differs from the \"\n+                        \"CRS of current GeoDataFrame (EPSG:{epsg_src}).\".format(\n+                            epsg_t=target_srid, epsg_src=srid\n+                        )\n+                    )\n+                    raise ValueError(msg)\n \n     with con.begin() as connection:\n", "issue": "Append to PostGIS table not working when table does not exist \n@jorisvandenbossche @martinfleis \r\nWhen table does not exist in the PostGIS database, using the `if_exists=\"append\"` raises an error because SRID check is attempted from non-existing table.\r\n\r\nFix is on the way. \n", "before_files": [{"content": "import warnings\n\nimport pandas as pd\n\nimport shapely.wkb\n\nfrom geopandas import GeoDataFrame\n\nfrom .. import _compat as compat\n\n\ndef _read_postgis(\n    sql,\n    con,\n    geom_col=\"geom\",\n    crs=None,\n    index_col=None,\n    coerce_float=True,\n    parse_dates=None,\n    params=None,\n):\n    \"\"\"\n    Returns a GeoDataFrame corresponding to the result of the query\n    string, which must contain a geometry column in WKB representation.\n\n    Parameters\n    ----------\n    sql : string\n        SQL query to execute in selecting entries from database, or name\n        of the table to read from the database.\n    con : DB connection object or SQLAlchemy engine\n        Active connection to the database to query.\n    geom_col : string, default 'geom'\n        column name to convert to shapely geometries\n    crs : pyproj.CRS, optional\n        CRS to use for the returned GeoDataFrame. The value can be anything accepted\n        by :meth:`pyproj.CRS.from_user_input() <pyproj.crs.CRS.from_user_input>`,\n        such as an authority string (eg \"EPSG:4326\") or a WKT string.\n        If not set, tries to determine CRS from the SRID associated with the\n        first geometry in the database, and assigns that to all geometries.\n\n    See the documentation for pandas.read_sql for further explanation\n    of the following parameters:\n    index_col, coerce_float, parse_dates, params\n\n    Returns\n    -------\n    GeoDataFrame\n\n    Example\n    -------\n    PostGIS\n    >>> sql = \"SELECT geom, kind FROM polygons\"\n    SpatiaLite\n    >>> sql = \"SELECT ST_AsBinary(geom) AS geom, kind FROM polygons\"\n    >>> df = geopandas.read_postgis(sql, con)\n    \"\"\"\n\n    df = pd.read_sql(\n        sql,\n        con,\n        index_col=index_col,\n        coerce_float=coerce_float,\n        parse_dates=parse_dates,\n        params=params,\n    )\n\n    if geom_col not in df:\n        raise ValueError(\"Query missing geometry column '{}'\".format(geom_col))\n\n    geoms = df[geom_col].dropna()\n\n    if not geoms.empty:\n        load_geom_bytes = shapely.wkb.loads\n        \"\"\"Load from Python 3 binary.\"\"\"\n\n        def load_geom_buffer(x):\n            \"\"\"Load from Python 2 binary.\"\"\"\n            return shapely.wkb.loads(str(x))\n\n        def load_geom_text(x):\n            \"\"\"Load from binary encoded as text.\"\"\"\n            return shapely.wkb.loads(str(x), hex=True)\n\n        if isinstance(geoms.iat[0], bytes):\n            load_geom = load_geom_bytes\n        else:\n            load_geom = load_geom_text\n\n        df[geom_col] = geoms = geoms.apply(load_geom)\n        if crs is None:\n            srid = shapely.geos.lgeos.GEOSGetSRID(geoms.iat[0]._geom)\n            # if no defined SRID in geodatabase, returns SRID of 0\n            if srid != 0:\n                crs = \"epsg:{}\".format(srid)\n\n    return GeoDataFrame(df, crs=crs, geometry=geom_col)\n\n\ndef read_postgis(*args, **kwargs):\n    import warnings\n\n    warnings.warn(\n        \"geopandas.io.sql.read_postgis() is intended for internal \"\n        \"use only, and will be deprecated. Use geopandas.read_postgis() instead.\",\n        DeprecationWarning,\n        stacklevel=2,\n    )\n\n    return _read_postgis(*args, **kwargs)\n\n\ndef _get_geometry_type(gdf):\n    \"\"\"\n    Get basic geometry type of a GeoDataFrame. See more info from:\n    https://geoalchemy-2.readthedocs.io/en/latest/types.html#geoalchemy2.types._GISType\n\n    Following rules apply:\n     - if geometries all share the same geometry-type,\n       geometries are inserted with the given GeometryType with following types:\n        - Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon,\n          GeometryCollection.\n        - LinearRing geometries will be converted into LineString -objects.\n     - in all other cases, geometries will be inserted with type GEOMETRY:\n        - a mix of Polygons and MultiPolygons in GeoSeries\n        - a mix of Points and LineStrings in GeoSeries\n        - geometry is of type GeometryCollection,\n          such as GeometryCollection([Point, LineStrings])\n     - if any of the geometries has Z-coordinate, all records will\n       be written with 3D.\n     \"\"\"\n    geom_types = list(gdf.geometry.geom_type.unique())\n    has_curve = False\n\n    for gt in geom_types:\n        if gt is None:\n            continue\n        elif \"LinearRing\" in gt:\n            has_curve = True\n\n    if len(geom_types) == 1:\n        if has_curve:\n            target_geom_type = \"LINESTRING\"\n        else:\n            if geom_types[0] is None:\n                raise ValueError(\"No valid geometries in the data.\")\n            else:\n                target_geom_type = geom_types[0].upper()\n    else:\n        target_geom_type = \"GEOMETRY\"\n\n    # Check for 3D-coordinates\n    if any(gdf.geometry.has_z):\n        target_geom_type = target_geom_type + \"Z\"\n\n    return target_geom_type, has_curve\n\n\ndef _get_srid_from_crs(gdf):\n    \"\"\"\n    Get EPSG code from CRS if available. If not, return -1.\n    \"\"\"\n\n    # Use geoalchemy2 default for srid\n    # Note: undefined srid in PostGIS is 0\n    srid = -1\n    warning_msg = (\n        \"Could not parse CRS from the GeoDataFrame. \"\n        + \"Inserting data without defined CRS.\",\n    )\n    if gdf.crs is not None:\n        try:\n            srid = gdf.crs.to_epsg(min_confidence=25)\n            if srid is None:\n                srid = -1\n                warnings.warn(warning_msg, UserWarning, stacklevel=2)\n        except Exception:\n            warnings.warn(warning_msg, UserWarning, stacklevel=2)\n    return srid\n\n\ndef _convert_linearring_to_linestring(gdf, geom_name):\n    from shapely.geometry import LineString\n\n    # Todo: Use Pygeos function once it's implemented:\n    #  https://github.com/pygeos/pygeos/issues/76\n\n    mask = gdf.geom_type == \"LinearRing\"\n    gdf.loc[mask, geom_name] = gdf.loc[mask, geom_name].apply(\n        lambda geom: LineString(geom)\n    )\n    return gdf\n\n\ndef _convert_to_ewkb(gdf, geom_name, srid):\n    \"\"\"Convert geometries to ewkb. \"\"\"\n    if compat.USE_PYGEOS:\n        from pygeos import set_srid, to_wkb\n\n        geoms = to_wkb(\n            set_srid(gdf[geom_name].values.data, srid=srid), hex=True, include_srid=True\n        )\n\n    else:\n        from shapely.wkb import dumps\n\n        geoms = [dumps(geom, srid=srid, hex=True) for geom in gdf[geom_name]]\n\n    gdf[geom_name] = geoms\n    return gdf\n\n\ndef _psql_insert_copy(tbl, conn, keys, data_iter):\n    import io\n    import csv\n\n    s_buf = io.StringIO()\n    writer = csv.writer(s_buf)\n    writer.writerows(data_iter)\n    s_buf.seek(0)\n\n    columns = \", \".join('\"{}\"'.format(k) for k in keys)\n\n    dbapi_conn = conn.connection\n    with dbapi_conn.cursor() as cur:\n        sql = \"COPY {} ({}) FROM STDIN WITH CSV\".format(tbl.table.fullname, columns)\n        cur.copy_expert(sql=sql, file=s_buf)\n\n\ndef _write_postgis(\n    gdf,\n    name,\n    con,\n    schema=None,\n    if_exists=\"fail\",\n    index=False,\n    index_label=None,\n    chunksize=None,\n    dtype=None,\n):\n    \"\"\"\n    Upload GeoDataFrame into PostGIS database.\n\n    This method requires SQLAlchemy and GeoAlchemy2, and a PostgreSQL\n    Python driver (e.g. psycopg2) to be installed.\n\n    Parameters\n    ----------\n    name : str\n        Name of the target table.\n    con : sqlalchemy.engine.Engine\n        Active connection to the PostGIS database.\n    if_exists : {'fail', 'replace', 'append'}, default 'fail'\n        How to behave if the table already exists:\n\n        - fail: Raise a ValueError.\n        - replace: Drop the table before inserting new values.\n        - append: Insert new values to the existing table.\n    schema : string, optional\n        Specify the schema. If None, use default schema: 'public'.\n    index : bool, default True\n        Write DataFrame index as a column.\n        Uses *index_label* as the column name in the table.\n    index_label : string or sequence, default None\n        Column label for index column(s).\n        If None is given (default) and index is True,\n        then the index names are used.\n    chunksize : int, optional\n        Rows will be written in batches of this size at a time.\n        By default, all rows will be written at once.\n    dtype : dict of column name to SQL type, default None\n        Specifying the datatype for columns.\n        The keys should be the column names and the values\n        should be the SQLAlchemy types.\n\n    Examples\n    --------\n\n    >>> from sqlalchemy import create_engine\n    >>> engine = create_engine(\"postgres://myusername:mypassword@myhost:5432\\\n/mydatabase\";)\n    >>> gdf.to_postgis(\"my_table\", engine)\n    \"\"\"\n    try:\n        from geoalchemy2 import Geometry\n    except ImportError:\n        raise ImportError(\"'to_postgis()' requires geoalchemy2 package. \")\n\n    if not compat.SHAPELY_GE_17:\n        raise ImportError(\n            \"'to_postgis()' requires newer version of Shapely \"\n            \"(>= '1.7.0').\\nYou can update the library using \"\n            \"'pip install shapely --upgrade' or using \"\n            \"'conda update shapely' if using conda package manager.\"\n        )\n\n    gdf = gdf.copy()\n    geom_name = gdf.geometry.name\n\n    # Get srid\n    srid = _get_srid_from_crs(gdf)\n\n    # Get geometry type and info whether data contains LinearRing.\n    geometry_type, has_curve = _get_geometry_type(gdf)\n\n    # Build dtype with Geometry\n    if dtype is not None:\n        dtype[geom_name] = Geometry(geometry_type=geometry_type, srid=srid)\n    else:\n        dtype = {geom_name: Geometry(geometry_type=geometry_type, srid=srid)}\n\n    # Convert LinearRing geometries to LineString\n    if has_curve:\n        gdf = _convert_linearring_to_linestring(gdf, geom_name)\n\n    # Convert geometries to EWKB\n    gdf = _convert_to_ewkb(gdf, geom_name, srid)\n\n    if if_exists == \"append\":\n        # Check that the geometry srid matches with the current GeoDataFrame\n        with con.begin() as connection:\n            if schema is not None:\n                schema_name = schema\n            else:\n                schema_name = \"public\"\n\n            target_srid = connection.execute(\n                \"SELECT Find_SRID('{schema}', '{table}', '{geom_col}');\".format(\n                    schema=schema_name, table=name, geom_col=geom_name\n                )\n            ).fetchone()[0]\n\n            if target_srid != srid:\n                msg = (\n                    \"The CRS of the target table (EPSG:{epsg_t}) differs from the \"\n                    \"CRS of current GeoDataFrame (EPSG:{epsg_src}).\".format(\n                        epsg_t=target_srid, epsg_src=srid\n                    )\n                )\n                raise ValueError(msg)\n\n    with con.begin() as connection:\n\n        gdf.to_sql(\n            name,\n            connection,\n            schema=schema,\n            if_exists=if_exists,\n            index=index,\n            index_label=index_label,\n            chunksize=chunksize,\n            dtype=dtype,\n            method=_psql_insert_copy,\n        )\n\n    return\n", "path": "geopandas/io/sql.py"}], "after_files": [{"content": "import warnings\n\nimport pandas as pd\n\nimport shapely.wkb\n\nfrom geopandas import GeoDataFrame\n\nfrom .. import _compat as compat\n\n\ndef _read_postgis(\n    sql,\n    con,\n    geom_col=\"geom\",\n    crs=None,\n    index_col=None,\n    coerce_float=True,\n    parse_dates=None,\n    params=None,\n):\n    \"\"\"\n    Returns a GeoDataFrame corresponding to the result of the query\n    string, which must contain a geometry column in WKB representation.\n\n    Parameters\n    ----------\n    sql : string\n        SQL query to execute in selecting entries from database, or name\n        of the table to read from the database.\n    con : DB connection object or SQLAlchemy engine\n        Active connection to the database to query.\n    geom_col : string, default 'geom'\n        column name to convert to shapely geometries\n    crs : pyproj.CRS, optional\n        CRS to use for the returned GeoDataFrame. The value can be anything accepted\n        by :meth:`pyproj.CRS.from_user_input() <pyproj.crs.CRS.from_user_input>`,\n        such as an authority string (eg \"EPSG:4326\") or a WKT string.\n        If not set, tries to determine CRS from the SRID associated with the\n        first geometry in the database, and assigns that to all geometries.\n\n    See the documentation for pandas.read_sql for further explanation\n    of the following parameters:\n    index_col, coerce_float, parse_dates, params\n\n    Returns\n    -------\n    GeoDataFrame\n\n    Example\n    -------\n    PostGIS\n    >>> sql = \"SELECT geom, kind FROM polygons\"\n    SpatiaLite\n    >>> sql = \"SELECT ST_AsBinary(geom) AS geom, kind FROM polygons\"\n    >>> df = geopandas.read_postgis(sql, con)\n    \"\"\"\n\n    df = pd.read_sql(\n        sql,\n        con,\n        index_col=index_col,\n        coerce_float=coerce_float,\n        parse_dates=parse_dates,\n        params=params,\n    )\n\n    if geom_col not in df:\n        raise ValueError(\"Query missing geometry column '{}'\".format(geom_col))\n\n    geoms = df[geom_col].dropna()\n\n    if not geoms.empty:\n        load_geom_bytes = shapely.wkb.loads\n        \"\"\"Load from Python 3 binary.\"\"\"\n\n        def load_geom_buffer(x):\n            \"\"\"Load from Python 2 binary.\"\"\"\n            return shapely.wkb.loads(str(x))\n\n        def load_geom_text(x):\n            \"\"\"Load from binary encoded as text.\"\"\"\n            return shapely.wkb.loads(str(x), hex=True)\n\n        if isinstance(geoms.iat[0], bytes):\n            load_geom = load_geom_bytes\n        else:\n            load_geom = load_geom_text\n\n        df[geom_col] = geoms = geoms.apply(load_geom)\n        if crs is None:\n            srid = shapely.geos.lgeos.GEOSGetSRID(geoms.iat[0]._geom)\n            # if no defined SRID in geodatabase, returns SRID of 0\n            if srid != 0:\n                crs = \"epsg:{}\".format(srid)\n\n    return GeoDataFrame(df, crs=crs, geometry=geom_col)\n\n\ndef read_postgis(*args, **kwargs):\n    import warnings\n\n    warnings.warn(\n        \"geopandas.io.sql.read_postgis() is intended for internal \"\n        \"use only, and will be deprecated. Use geopandas.read_postgis() instead.\",\n        DeprecationWarning,\n        stacklevel=2,\n    )\n\n    return _read_postgis(*args, **kwargs)\n\n\ndef _get_geometry_type(gdf):\n    \"\"\"\n    Get basic geometry type of a GeoDataFrame. See more info from:\n    https://geoalchemy-2.readthedocs.io/en/latest/types.html#geoalchemy2.types._GISType\n\n    Following rules apply:\n     - if geometries all share the same geometry-type,\n       geometries are inserted with the given GeometryType with following types:\n        - Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon,\n          GeometryCollection.\n        - LinearRing geometries will be converted into LineString -objects.\n     - in all other cases, geometries will be inserted with type GEOMETRY:\n        - a mix of Polygons and MultiPolygons in GeoSeries\n        - a mix of Points and LineStrings in GeoSeries\n        - geometry is of type GeometryCollection,\n          such as GeometryCollection([Point, LineStrings])\n     - if any of the geometries has Z-coordinate, all records will\n       be written with 3D.\n     \"\"\"\n    geom_types = list(gdf.geometry.geom_type.unique())\n    has_curve = False\n\n    for gt in geom_types:\n        if gt is None:\n            continue\n        elif \"LinearRing\" in gt:\n            has_curve = True\n\n    if len(geom_types) == 1:\n        if has_curve:\n            target_geom_type = \"LINESTRING\"\n        else:\n            if geom_types[0] is None:\n                raise ValueError(\"No valid geometries in the data.\")\n            else:\n                target_geom_type = geom_types[0].upper()\n    else:\n        target_geom_type = \"GEOMETRY\"\n\n    # Check for 3D-coordinates\n    if any(gdf.geometry.has_z):\n        target_geom_type = target_geom_type + \"Z\"\n\n    return target_geom_type, has_curve\n\n\ndef _get_srid_from_crs(gdf):\n    \"\"\"\n    Get EPSG code from CRS if available. If not, return -1.\n    \"\"\"\n\n    # Use geoalchemy2 default for srid\n    # Note: undefined srid in PostGIS is 0\n    srid = -1\n    warning_msg = (\n        \"Could not parse CRS from the GeoDataFrame. \"\n        + \"Inserting data without defined CRS.\",\n    )\n    if gdf.crs is not None:\n        try:\n            srid = gdf.crs.to_epsg(min_confidence=25)\n            if srid is None:\n                srid = -1\n                warnings.warn(warning_msg, UserWarning, stacklevel=2)\n        except Exception:\n            warnings.warn(warning_msg, UserWarning, stacklevel=2)\n    return srid\n\n\ndef _convert_linearring_to_linestring(gdf, geom_name):\n    from shapely.geometry import LineString\n\n    # Todo: Use Pygeos function once it's implemented:\n    #  https://github.com/pygeos/pygeos/issues/76\n\n    mask = gdf.geom_type == \"LinearRing\"\n    gdf.loc[mask, geom_name] = gdf.loc[mask, geom_name].apply(\n        lambda geom: LineString(geom)\n    )\n    return gdf\n\n\ndef _convert_to_ewkb(gdf, geom_name, srid):\n    \"\"\"Convert geometries to ewkb. \"\"\"\n    if compat.USE_PYGEOS:\n        from pygeos import set_srid, to_wkb\n\n        geoms = to_wkb(\n            set_srid(gdf[geom_name].values.data, srid=srid), hex=True, include_srid=True\n        )\n\n    else:\n        from shapely.wkb import dumps\n\n        geoms = [dumps(geom, srid=srid, hex=True) for geom in gdf[geom_name]]\n\n    gdf[geom_name] = geoms\n    return gdf\n\n\ndef _psql_insert_copy(tbl, conn, keys, data_iter):\n    import io\n    import csv\n\n    s_buf = io.StringIO()\n    writer = csv.writer(s_buf)\n    writer.writerows(data_iter)\n    s_buf.seek(0)\n\n    columns = \", \".join('\"{}\"'.format(k) for k in keys)\n\n    dbapi_conn = conn.connection\n    with dbapi_conn.cursor() as cur:\n        sql = \"COPY {} ({}) FROM STDIN WITH CSV\".format(tbl.table.fullname, columns)\n        cur.copy_expert(sql=sql, file=s_buf)\n\n\ndef _write_postgis(\n    gdf,\n    name,\n    con,\n    schema=None,\n    if_exists=\"fail\",\n    index=False,\n    index_label=None,\n    chunksize=None,\n    dtype=None,\n):\n    \"\"\"\n    Upload GeoDataFrame into PostGIS database.\n\n    This method requires SQLAlchemy and GeoAlchemy2, and a PostgreSQL\n    Python driver (e.g. psycopg2) to be installed.\n\n    Parameters\n    ----------\n    name : str\n        Name of the target table.\n    con : sqlalchemy.engine.Engine\n        Active connection to the PostGIS database.\n    if_exists : {'fail', 'replace', 'append'}, default 'fail'\n        How to behave if the table already exists:\n\n        - fail: Raise a ValueError.\n        - replace: Drop the table before inserting new values.\n        - append: Insert new values to the existing table.\n    schema : string, optional\n        Specify the schema. If None, use default schema: 'public'.\n    index : bool, default True\n        Write DataFrame index as a column.\n        Uses *index_label* as the column name in the table.\n    index_label : string or sequence, default None\n        Column label for index column(s).\n        If None is given (default) and index is True,\n        then the index names are used.\n    chunksize : int, optional\n        Rows will be written in batches of this size at a time.\n        By default, all rows will be written at once.\n    dtype : dict of column name to SQL type, default None\n        Specifying the datatype for columns.\n        The keys should be the column names and the values\n        should be the SQLAlchemy types.\n\n    Examples\n    --------\n\n    >>> from sqlalchemy import create_engine\n    >>> engine = create_engine(\"postgres://myusername:mypassword@myhost:5432\\\n/mydatabase\";)\n    >>> gdf.to_postgis(\"my_table\", engine)\n    \"\"\"\n    try:\n        from geoalchemy2 import Geometry\n    except ImportError:\n        raise ImportError(\"'to_postgis()' requires geoalchemy2 package. \")\n\n    if not compat.SHAPELY_GE_17:\n        raise ImportError(\n            \"'to_postgis()' requires newer version of Shapely \"\n            \"(>= '1.7.0').\\nYou can update the library using \"\n            \"'pip install shapely --upgrade' or using \"\n            \"'conda update shapely' if using conda package manager.\"\n        )\n\n    gdf = gdf.copy()\n    geom_name = gdf.geometry.name\n\n    # Get srid\n    srid = _get_srid_from_crs(gdf)\n\n    # Get geometry type and info whether data contains LinearRing.\n    geometry_type, has_curve = _get_geometry_type(gdf)\n\n    # Build dtype with Geometry\n    if dtype is not None:\n        dtype[geom_name] = Geometry(geometry_type=geometry_type, srid=srid)\n    else:\n        dtype = {geom_name: Geometry(geometry_type=geometry_type, srid=srid)}\n\n    # Convert LinearRing geometries to LineString\n    if has_curve:\n        gdf = _convert_linearring_to_linestring(gdf, geom_name)\n\n    # Convert geometries to EWKB\n    gdf = _convert_to_ewkb(gdf, geom_name, srid)\n\n    if if_exists == \"append\":\n        # Check that the geometry srid matches with the current GeoDataFrame\n        with con.begin() as connection:\n            if schema is not None:\n                schema_name = schema\n            else:\n                schema_name = \"public\"\n\n            # Only check SRID if table exists\n            if connection.run_callable(connection.dialect.has_table, name, schema):\n                target_srid = connection.execute(\n                    \"SELECT Find_SRID('{schema}', '{table}', '{geom_col}');\".format(\n                        schema=schema_name, table=name, geom_col=geom_name\n                    )\n                ).fetchone()[0]\n\n                if target_srid != srid:\n                    msg = (\n                        \"The CRS of the target table (EPSG:{epsg_t}) differs from the \"\n                        \"CRS of current GeoDataFrame (EPSG:{epsg_src}).\".format(\n                            epsg_t=target_srid, epsg_src=srid\n                        )\n                    )\n                    raise ValueError(msg)\n\n    with con.begin() as connection:\n\n        gdf.to_sql(\n            name,\n            connection,\n            schema=schema,\n            if_exists=if_exists,\n            index=index,\n            index_label=index_label,\n            chunksize=chunksize,\n            dtype=dtype,\n            method=_psql_insert_copy,\n        )\n\n    return\n", "path": "geopandas/io/sql.py"}]}