We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
postgresql_db inverts the 'changed' logic in check mode when state=absent
##### ISSUE TYPE
- Bug Report
##### COMPONENT NAME

postgresql_db
##### ANSIBLE VERSION

```
ansible 2.1.1.0
  config file = 
  configured module search path = Default w/o overrides
```
##### SUMMARY

I've a task that tries to remove a PostgreSQL database.  When I run it in --check mode, it says "changed" if the database doesn't exist, and says "not changed" if the database exists. This is exactly the opposite of what it should say.

<!--
##### STEPS TO REPRODUCE

```

```

##### EXPECTED RESULTS

##### ACTUAL RESULTS
```

```
-->


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `database/postgresql/postgresql_db.py`
Content:
```
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 
4 # This file is part of Ansible
5 #
6 # Ansible is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # Ansible is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
18 
19 DOCUMENTATION = '''
20 ---
21 module: postgresql_db
22 short_description: Add or remove PostgreSQL databases from a remote host.
23 description:
24    - Add or remove PostgreSQL databases from a remote host.
25 version_added: "0.6"
26 options:
27   name:
28     description:
29       - name of the database to add or remove
30     required: true
31     default: null
32   login_user:
33     description:
34       - The username used to authenticate with
35     required: false
36     default: null
37   login_password:
38     description:
39       - The password used to authenticate with
40     required: false
41     default: null
42   login_host:
43     description:
44       - Host running the database
45     required: false
46     default: localhost
47   login_unix_socket:
48     description:
49       - Path to a Unix domain socket for local connections
50     required: false
51     default: null
52   owner:
53     description:
54       - Name of the role to set as owner of the database
55     required: false
56     default: null
57   port:
58     description:
59       - Database port to connect to.
60     required: false
61     default: 5432
62   template:
63     description:
64       - Template used to create the database
65     required: false
66     default: null
67   encoding:
68     description:
69       - Encoding of the database
70     required: false
71     default: null
72   lc_collate:
73     description:
74       - Collation order (LC_COLLATE) to use in the database. Must match collation order of template database unless C(template0) is used as template.
75     required: false
76     default: null
77   lc_ctype:
78     description:
79       - Character classification (LC_CTYPE) to use in the database (e.g. lower, upper, ...) Must match LC_CTYPE of template database unless C(template0) is used as template.
80     required: false
81     default: null
82   state:
83     description:
84       - The database state
85     required: false
86     default: present
87     choices: [ "present", "absent" ]
88 notes:
89    - The default authentication assumes that you are either logging in as or sudo'ing to the C(postgres) account on the host.
90    - This module uses I(psycopg2), a Python PostgreSQL database adapter. You must ensure that psycopg2 is installed on
91      the host before using this module. If the remote host is the PostgreSQL server (which is the default case), then PostgreSQL must also be installed on the remote host. For Ubuntu-based systems, install the C(postgresql), C(libpq-dev), and C(python-psycopg2) packages on the remote host before using this module.
92 requirements: [ psycopg2 ]
93 author: "Ansible Core Team"
94 '''
95 
96 EXAMPLES = '''
97 # Create a new database with name "acme"
98 - postgresql_db: name=acme
99 
100 # Create a new database with name "acme" and specific encoding and locale
101 # settings. If a template different from "template0" is specified, encoding
102 # and locale settings must match those of the template.
103 - postgresql_db: name=acme
104                  encoding='UTF-8'
105                  lc_collate='de_DE.UTF-8'
106                  lc_ctype='de_DE.UTF-8'
107                  template='template0'
108 '''
109 
110 try:
111     import psycopg2
112     import psycopg2.extras
113 except ImportError:
114     postgresqldb_found = False
115 else:
116     postgresqldb_found = True
117 from ansible.module_utils.six import iteritems
118 
119 class NotSupportedError(Exception):
120     pass
121 
122 
123 # ===========================================
124 # PostgreSQL module specific support methods.
125 #
126 
127 def set_owner(cursor, db, owner):
128     query = "ALTER DATABASE %s OWNER TO %s" % (
129             pg_quote_identifier(db, 'database'),
130             pg_quote_identifier(owner, 'role'))
131     cursor.execute(query)
132     return True
133 
134 def get_encoding_id(cursor, encoding):
135     query = "SELECT pg_char_to_encoding(%(encoding)s) AS encoding_id;"
136     cursor.execute(query, {'encoding': encoding})
137     return cursor.fetchone()['encoding_id']
138 
139 def get_db_info(cursor, db):
140     query = """
141     SELECT rolname AS owner,
142     pg_encoding_to_char(encoding) AS encoding, encoding AS encoding_id,
143     datcollate AS lc_collate, datctype AS lc_ctype
144     FROM pg_database JOIN pg_roles ON pg_roles.oid = pg_database.datdba
145     WHERE datname = %(db)s
146     """
147     cursor.execute(query, {'db': db})
148     return cursor.fetchone()
149 
150 def db_exists(cursor, db):
151     query = "SELECT * FROM pg_database WHERE datname=%(db)s"
152     cursor.execute(query, {'db': db})
153     return cursor.rowcount == 1
154 
155 def db_delete(cursor, db):
156     if db_exists(cursor, db):
157         query = "DROP DATABASE %s" % pg_quote_identifier(db, 'database')
158         cursor.execute(query)
159         return True
160     else:
161         return False
162 
163 def db_create(cursor, db, owner, template, encoding, lc_collate, lc_ctype):
164     params = dict(enc=encoding, collate=lc_collate, ctype=lc_ctype)
165     if not db_exists(cursor, db):
166         query_fragments = ['CREATE DATABASE %s' % pg_quote_identifier(db, 'database')]
167         if owner:
168             query_fragments.append('OWNER %s' % pg_quote_identifier(owner, 'role'))
169         if template:
170             query_fragments.append('TEMPLATE %s' % pg_quote_identifier(template, 'database'))
171         if encoding:
172             query_fragments.append('ENCODING %(enc)s')
173         if lc_collate:
174             query_fragments.append('LC_COLLATE %(collate)s')
175         if lc_ctype:
176             query_fragments.append('LC_CTYPE %(ctype)s')
177         query = ' '.join(query_fragments)
178         cursor.execute(query, params)
179         return True
180     else:
181         db_info = get_db_info(cursor, db)
182         if (encoding and
183             get_encoding_id(cursor, encoding) != db_info['encoding_id']):
184             raise NotSupportedError(
185                 'Changing database encoding is not supported. '
186                 'Current encoding: %s' % db_info['encoding']
187             )
188         elif lc_collate and lc_collate != db_info['lc_collate']:
189             raise NotSupportedError(
190                 'Changing LC_COLLATE is not supported. '
191                 'Current LC_COLLATE: %s' % db_info['lc_collate']
192             )
193         elif lc_ctype and lc_ctype != db_info['lc_ctype']:
194             raise NotSupportedError(
195                 'Changing LC_CTYPE is not supported.'
196                 'Current LC_CTYPE: %s' % db_info['lc_ctype']
197             )
198         elif owner and owner != db_info['owner']:
199             return set_owner(cursor, db, owner)
200         else:
201             return False
202 
203 def db_matches(cursor, db, owner, template, encoding, lc_collate, lc_ctype):
204     if not db_exists(cursor, db):
205        return False
206     else:
207         db_info = get_db_info(cursor, db)
208         if (encoding and
209             get_encoding_id(cursor, encoding) != db_info['encoding_id']):
210             return False
211         elif lc_collate and lc_collate != db_info['lc_collate']:
212             return False
213         elif lc_ctype and lc_ctype != db_info['lc_ctype']:
214             return False
215         elif owner and owner != db_info['owner']:
216             return False
217         else:
218             return True
219 
220 # ===========================================
221 # Module execution.
222 #
223 
224 def main():
225     module = AnsibleModule(
226         argument_spec=dict(
227             login_user=dict(default="postgres"),
228             login_password=dict(default=""),
229             login_host=dict(default=""),
230             login_unix_socket=dict(default=""),
231             port=dict(default="5432"),
232             db=dict(required=True, aliases=['name']),
233             owner=dict(default=""),
234             template=dict(default=""),
235             encoding=dict(default=""),
236             lc_collate=dict(default=""),
237             lc_ctype=dict(default=""),
238             state=dict(default="present", choices=["absent", "present"]),
239         ),
240         supports_check_mode = True
241     )
242 
243     if not postgresqldb_found:
244         module.fail_json(msg="the python psycopg2 module is required")
245 
246     db = module.params["db"]
247     port = module.params["port"]
248     owner = module.params["owner"]
249     template = module.params["template"]
250     encoding = module.params["encoding"]
251     lc_collate = module.params["lc_collate"]
252     lc_ctype = module.params["lc_ctype"]
253     state = module.params["state"]
254     changed = False
255 
256     # To use defaults values, keyword arguments must be absent, so
257     # check which values are empty and don't include in the **kw
258     # dictionary
259     params_map = {
260         "login_host":"host",
261         "login_user":"user",
262         "login_password":"password",
263         "port":"port"
264     }
265     kw = dict( (params_map[k], v) for (k, v) in iteritems(module.params)
266               if k in params_map and v != '' )
267 
268     # If a login_unix_socket is specified, incorporate it here.
269     is_localhost = "host" not in kw or kw["host"] == "" or kw["host"] == "localhost"
270     if is_localhost and module.params["login_unix_socket"] != "":
271         kw["host"] = module.params["login_unix_socket"]
272 
273     try:
274         db_connection = psycopg2.connect(database="postgres", **kw)
275         # Enable autocommit so we can create databases
276         if psycopg2.__version__ >= '2.4.2':
277             db_connection.autocommit = True
278         else:
279             db_connection.set_isolation_level(psycopg2
280                                               .extensions
281                                               .ISOLATION_LEVEL_AUTOCOMMIT)
282         cursor = db_connection.cursor(
283                 cursor_factory=psycopg2.extras.DictCursor)
284     except Exception:
285         e = get_exception()
286         module.fail_json(msg="unable to connect to database: %s" % e)
287 
288     try:
289         if module.check_mode:
290             if state == "absent":
291                 changed = not db_exists(cursor, db)
292             elif state == "present":
293                 changed = not db_matches(cursor, db, owner, template, encoding,
294                                          lc_collate, lc_ctype)
295             module.exit_json(changed=changed,db=db)
296 
297         if state == "absent":
298             try:
299                 changed = db_delete(cursor, db)
300             except SQLParseError:
301                 e = get_exception()
302                 module.fail_json(msg=str(e))
303 
304         elif state == "present":
305             try:
306                 changed = db_create(cursor, db, owner, template, encoding,
307                                 lc_collate, lc_ctype)
308             except SQLParseError:
309                 e = get_exception()
310                 module.fail_json(msg=str(e))
311     except NotSupportedError:
312         e = get_exception()
313         module.fail_json(msg=str(e))
314     except SystemExit:
315         # Avoid catching this on Python 2.4 
316         raise
317     except Exception:
318         e = get_exception()
319         module.fail_json(msg="Database query failed: %s" % e)
320 
321     module.exit_json(changed=changed, db=db)
322 
323 # import module snippets
324 from ansible.module_utils.basic import *
325 from ansible.module_utils.database import *
326 if __name__ == '__main__':
327     main()
328
```
--- 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/database/postgresql/postgresql_db.py b/database/postgresql/postgresql_db.py
old mode 100644
new mode 100755
--- a/database/postgresql/postgresql_db.py
+++ b/database/postgresql/postgresql_db.py
@@ -288,11 +288,11 @@
     try:
         if module.check_mode:
             if state == "absent":
-                changed = not db_exists(cursor, db)
+                changed = db_exists(cursor, db)
             elif state == "present":
                 changed = not db_matches(cursor, db, owner, template, encoding,
                                          lc_collate, lc_ctype)
-            module.exit_json(changed=changed,db=db)
+            module.exit_json(changed=changed, db=db)
 
         if state == "absent":
             try:

{"golden_diff": "diff --git a/database/postgresql/postgresql_db.py b/database/postgresql/postgresql_db.py\nold mode 100644\nnew mode 100755\n--- a/database/postgresql/postgresql_db.py\n+++ b/database/postgresql/postgresql_db.py\n@@ -288,11 +288,11 @@\n     try:\n         if module.check_mode:\n             if state == \"absent\":\n-                changed = not db_exists(cursor, db)\n+                changed = db_exists(cursor, db)\n             elif state == \"present\":\n                 changed = not db_matches(cursor, db, owner, template, encoding,\n                                          lc_collate, lc_ctype)\n-            module.exit_json(changed=changed,db=db)\n+            module.exit_json(changed=changed, db=db)\n \n         if state == \"absent\":\n             try:\n", "issue": "postgresql_db inverts the 'changed' logic in check mode when state=absent\n##### ISSUE TYPE\n- Bug Report\n##### COMPONENT NAME\n\npostgresql_db\n##### ANSIBLE VERSION\n\n```\nansible 2.1.1.0\n  config file = \n  configured module search path = Default w/o overrides\n```\n##### SUMMARY\n\nI've a task that tries to remove a PostgreSQL database.  When I run it in --check mode, it says \"changed\" if the database doesn't exist, and says \"not changed\" if the database exists. This is exactly the opposite of what it should say.\n\n<!--\n##### STEPS TO REPRODUCE\n\n```\n\n```\n\n##### EXPECTED RESULTS\n\n##### ACTUAL RESULTS\n```\n\n```\n-->\n\n", "before_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# This file is part of Ansible\n#\n# Ansible is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Ansible is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.\n\nDOCUMENTATION = '''\n---\nmodule: postgresql_db\nshort_description: Add or remove PostgreSQL databases from a remote host.\ndescription:\n   - Add or remove PostgreSQL databases from a remote host.\nversion_added: \"0.6\"\noptions:\n  name:\n    description:\n      - name of the database to add or remove\n    required: true\n    default: null\n  login_user:\n    description:\n      - The username used to authenticate with\n    required: false\n    default: null\n  login_password:\n    description:\n      - The password used to authenticate with\n    required: false\n    default: null\n  login_host:\n    description:\n      - Host running the database\n    required: false\n    default: localhost\n  login_unix_socket:\n    description:\n      - Path to a Unix domain socket for local connections\n    required: false\n    default: null\n  owner:\n    description:\n      - Name of the role to set as owner of the database\n    required: false\n    default: null\n  port:\n    description:\n      - Database port to connect to.\n    required: false\n    default: 5432\n  template:\n    description:\n      - Template used to create the database\n    required: false\n    default: null\n  encoding:\n    description:\n      - Encoding of the database\n    required: false\n    default: null\n  lc_collate:\n    description:\n      - Collation order (LC_COLLATE) to use in the database. Must match collation order of template database unless C(template0) is used as template.\n    required: false\n    default: null\n  lc_ctype:\n    description:\n      - Character classification (LC_CTYPE) to use in the database (e.g. lower, upper, ...) Must match LC_CTYPE of template database unless C(template0) is used as template.\n    required: false\n    default: null\n  state:\n    description:\n      - The database state\n    required: false\n    default: present\n    choices: [ \"present\", \"absent\" ]\nnotes:\n   - The default authentication assumes that you are either logging in as or sudo'ing to the C(postgres) account on the host.\n   - This module uses I(psycopg2), a Python PostgreSQL database adapter. You must ensure that psycopg2 is installed on\n     the host before using this module. If the remote host is the PostgreSQL server (which is the default case), then PostgreSQL must also be installed on the remote host. For Ubuntu-based systems, install the C(postgresql), C(libpq-dev), and C(python-psycopg2) packages on the remote host before using this module.\nrequirements: [ psycopg2 ]\nauthor: \"Ansible Core Team\"\n'''\n\nEXAMPLES = '''\n# Create a new database with name \"acme\"\n- postgresql_db: name=acme\n\n# Create a new database with name \"acme\" and specific encoding and locale\n# settings. If a template different from \"template0\" is specified, encoding\n# and locale settings must match those of the template.\n- postgresql_db: name=acme\n                 encoding='UTF-8'\n                 lc_collate='de_DE.UTF-8'\n                 lc_ctype='de_DE.UTF-8'\n                 template='template0'\n'''\n\ntry:\n    import psycopg2\n    import psycopg2.extras\nexcept ImportError:\n    postgresqldb_found = False\nelse:\n    postgresqldb_found = True\nfrom ansible.module_utils.six import iteritems\n\nclass NotSupportedError(Exception):\n    pass\n\n\n# ===========================================\n# PostgreSQL module specific support methods.\n#\n\ndef set_owner(cursor, db, owner):\n    query = \"ALTER DATABASE %s OWNER TO %s\" % (\n            pg_quote_identifier(db, 'database'),\n            pg_quote_identifier(owner, 'role'))\n    cursor.execute(query)\n    return True\n\ndef get_encoding_id(cursor, encoding):\n    query = \"SELECT pg_char_to_encoding(%(encoding)s) AS encoding_id;\"\n    cursor.execute(query, {'encoding': encoding})\n    return cursor.fetchone()['encoding_id']\n\ndef get_db_info(cursor, db):\n    query = \"\"\"\n    SELECT rolname AS owner,\n    pg_encoding_to_char(encoding) AS encoding, encoding AS encoding_id,\n    datcollate AS lc_collate, datctype AS lc_ctype\n    FROM pg_database JOIN pg_roles ON pg_roles.oid = pg_database.datdba\n    WHERE datname = %(db)s\n    \"\"\"\n    cursor.execute(query, {'db': db})\n    return cursor.fetchone()\n\ndef db_exists(cursor, db):\n    query = \"SELECT * FROM pg_database WHERE datname=%(db)s\"\n    cursor.execute(query, {'db': db})\n    return cursor.rowcount == 1\n\ndef db_delete(cursor, db):\n    if db_exists(cursor, db):\n        query = \"DROP DATABASE %s\" % pg_quote_identifier(db, 'database')\n        cursor.execute(query)\n        return True\n    else:\n        return False\n\ndef db_create(cursor, db, owner, template, encoding, lc_collate, lc_ctype):\n    params = dict(enc=encoding, collate=lc_collate, ctype=lc_ctype)\n    if not db_exists(cursor, db):\n        query_fragments = ['CREATE DATABASE %s' % pg_quote_identifier(db, 'database')]\n        if owner:\n            query_fragments.append('OWNER %s' % pg_quote_identifier(owner, 'role'))\n        if template:\n            query_fragments.append('TEMPLATE %s' % pg_quote_identifier(template, 'database'))\n        if encoding:\n            query_fragments.append('ENCODING %(enc)s')\n        if lc_collate:\n            query_fragments.append('LC_COLLATE %(collate)s')\n        if lc_ctype:\n            query_fragments.append('LC_CTYPE %(ctype)s')\n        query = ' '.join(query_fragments)\n        cursor.execute(query, params)\n        return True\n    else:\n        db_info = get_db_info(cursor, db)\n        if (encoding and\n            get_encoding_id(cursor, encoding) != db_info['encoding_id']):\n            raise NotSupportedError(\n                'Changing database encoding is not supported. '\n                'Current encoding: %s' % db_info['encoding']\n            )\n        elif lc_collate and lc_collate != db_info['lc_collate']:\n            raise NotSupportedError(\n                'Changing LC_COLLATE is not supported. '\n                'Current LC_COLLATE: %s' % db_info['lc_collate']\n            )\n        elif lc_ctype and lc_ctype != db_info['lc_ctype']:\n            raise NotSupportedError(\n                'Changing LC_CTYPE is not supported.'\n                'Current LC_CTYPE: %s' % db_info['lc_ctype']\n            )\n        elif owner and owner != db_info['owner']:\n            return set_owner(cursor, db, owner)\n        else:\n            return False\n\ndef db_matches(cursor, db, owner, template, encoding, lc_collate, lc_ctype):\n    if not db_exists(cursor, db):\n       return False\n    else:\n        db_info = get_db_info(cursor, db)\n        if (encoding and\n            get_encoding_id(cursor, encoding) != db_info['encoding_id']):\n            return False\n        elif lc_collate and lc_collate != db_info['lc_collate']:\n            return False\n        elif lc_ctype and lc_ctype != db_info['lc_ctype']:\n            return False\n        elif owner and owner != db_info['owner']:\n            return False\n        else:\n            return True\n\n# ===========================================\n# Module execution.\n#\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=dict(\n            login_user=dict(default=\"postgres\"),\n            login_password=dict(default=\"\"),\n            login_host=dict(default=\"\"),\n            login_unix_socket=dict(default=\"\"),\n            port=dict(default=\"5432\"),\n            db=dict(required=True, aliases=['name']),\n            owner=dict(default=\"\"),\n            template=dict(default=\"\"),\n            encoding=dict(default=\"\"),\n            lc_collate=dict(default=\"\"),\n            lc_ctype=dict(default=\"\"),\n            state=dict(default=\"present\", choices=[\"absent\", \"present\"]),\n        ),\n        supports_check_mode = True\n    )\n\n    if not postgresqldb_found:\n        module.fail_json(msg=\"the python psycopg2 module is required\")\n\n    db = module.params[\"db\"]\n    port = module.params[\"port\"]\n    owner = module.params[\"owner\"]\n    template = module.params[\"template\"]\n    encoding = module.params[\"encoding\"]\n    lc_collate = module.params[\"lc_collate\"]\n    lc_ctype = module.params[\"lc_ctype\"]\n    state = module.params[\"state\"]\n    changed = False\n\n    # To use defaults values, keyword arguments must be absent, so\n    # check which values are empty and don't include in the **kw\n    # dictionary\n    params_map = {\n        \"login_host\":\"host\",\n        \"login_user\":\"user\",\n        \"login_password\":\"password\",\n        \"port\":\"port\"\n    }\n    kw = dict( (params_map[k], v) for (k, v) in iteritems(module.params)\n              if k in params_map and v != '' )\n\n    # If a login_unix_socket is specified, incorporate it here.\n    is_localhost = \"host\" not in kw or kw[\"host\"] == \"\" or kw[\"host\"] == \"localhost\"\n    if is_localhost and module.params[\"login_unix_socket\"] != \"\":\n        kw[\"host\"] = module.params[\"login_unix_socket\"]\n\n    try:\n        db_connection = psycopg2.connect(database=\"postgres\", **kw)\n        # Enable autocommit so we can create databases\n        if psycopg2.__version__ >= '2.4.2':\n            db_connection.autocommit = True\n        else:\n            db_connection.set_isolation_level(psycopg2\n                                              .extensions\n                                              .ISOLATION_LEVEL_AUTOCOMMIT)\n        cursor = db_connection.cursor(\n                cursor_factory=psycopg2.extras.DictCursor)\n    except Exception:\n        e = get_exception()\n        module.fail_json(msg=\"unable to connect to database: %s\" % e)\n\n    try:\n        if module.check_mode:\n            if state == \"absent\":\n                changed = not db_exists(cursor, db)\n            elif state == \"present\":\n                changed = not db_matches(cursor, db, owner, template, encoding,\n                                         lc_collate, lc_ctype)\n            module.exit_json(changed=changed,db=db)\n\n        if state == \"absent\":\n            try:\n                changed = db_delete(cursor, db)\n            except SQLParseError:\n                e = get_exception()\n                module.fail_json(msg=str(e))\n\n        elif state == \"present\":\n            try:\n                changed = db_create(cursor, db, owner, template, encoding,\n                                lc_collate, lc_ctype)\n            except SQLParseError:\n                e = get_exception()\n                module.fail_json(msg=str(e))\n    except NotSupportedError:\n        e = get_exception()\n        module.fail_json(msg=str(e))\n    except SystemExit:\n        # Avoid catching this on Python 2.4 \n        raise\n    except Exception:\n        e = get_exception()\n        module.fail_json(msg=\"Database query failed: %s\" % e)\n\n    module.exit_json(changed=changed, db=db)\n\n# import module snippets\nfrom ansible.module_utils.basic import *\nfrom ansible.module_utils.database import *\nif __name__ == '__main__':\n    main()\n", "path": "database/postgresql/postgresql_db.py"}], "after_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# This file is part of Ansible\n#\n# Ansible is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Ansible is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.\n\nDOCUMENTATION = '''\n---\nmodule: postgresql_db\nshort_description: Add or remove PostgreSQL databases from a remote host.\ndescription:\n   - Add or remove PostgreSQL databases from a remote host.\nversion_added: \"0.6\"\noptions:\n  name:\n    description:\n      - name of the database to add or remove\n    required: true\n    default: null\n  login_user:\n    description:\n      - The username used to authenticate with\n    required: false\n    default: null\n  login_password:\n    description:\n      - The password used to authenticate with\n    required: false\n    default: null\n  login_host:\n    description:\n      - Host running the database\n    required: false\n    default: localhost\n  login_unix_socket:\n    description:\n      - Path to a Unix domain socket for local connections\n    required: false\n    default: null\n  owner:\n    description:\n      - Name of the role to set as owner of the database\n    required: false\n    default: null\n  port:\n    description:\n      - Database port to connect to.\n    required: false\n    default: 5432\n  template:\n    description:\n      - Template used to create the database\n    required: false\n    default: null\n  encoding:\n    description:\n      - Encoding of the database\n    required: false\n    default: null\n  lc_collate:\n    description:\n      - Collation order (LC_COLLATE) to use in the database. Must match collation order of template database unless C(template0) is used as template.\n    required: false\n    default: null\n  lc_ctype:\n    description:\n      - Character classification (LC_CTYPE) to use in the database (e.g. lower, upper, ...) Must match LC_CTYPE of template database unless C(template0) is used as template.\n    required: false\n    default: null\n  state:\n    description:\n      - The database state\n    required: false\n    default: present\n    choices: [ \"present\", \"absent\" ]\nnotes:\n   - The default authentication assumes that you are either logging in as or sudo'ing to the C(postgres) account on the host.\n   - This module uses I(psycopg2), a Python PostgreSQL database adapter. You must ensure that psycopg2 is installed on\n     the host before using this module. If the remote host is the PostgreSQL server (which is the default case), then PostgreSQL must also be installed on the remote host. For Ubuntu-based systems, install the C(postgresql), C(libpq-dev), and C(python-psycopg2) packages on the remote host before using this module.\nrequirements: [ psycopg2 ]\nauthor: \"Ansible Core Team\"\n'''\n\nEXAMPLES = '''\n# Create a new database with name \"acme\"\n- postgresql_db: name=acme\n\n# Create a new database with name \"acme\" and specific encoding and locale\n# settings. If a template different from \"template0\" is specified, encoding\n# and locale settings must match those of the template.\n- postgresql_db: name=acme\n                 encoding='UTF-8'\n                 lc_collate='de_DE.UTF-8'\n                 lc_ctype='de_DE.UTF-8'\n                 template='template0'\n'''\n\ntry:\n    import psycopg2\n    import psycopg2.extras\nexcept ImportError:\n    postgresqldb_found = False\nelse:\n    postgresqldb_found = True\nfrom ansible.module_utils.six import iteritems\n\nclass NotSupportedError(Exception):\n    pass\n\n\n# ===========================================\n# PostgreSQL module specific support methods.\n#\n\ndef set_owner(cursor, db, owner):\n    query = \"ALTER DATABASE %s OWNER TO %s\" % (\n            pg_quote_identifier(db, 'database'),\n            pg_quote_identifier(owner, 'role'))\n    cursor.execute(query)\n    return True\n\ndef get_encoding_id(cursor, encoding):\n    query = \"SELECT pg_char_to_encoding(%(encoding)s) AS encoding_id;\"\n    cursor.execute(query, {'encoding': encoding})\n    return cursor.fetchone()['encoding_id']\n\ndef get_db_info(cursor, db):\n    query = \"\"\"\n    SELECT rolname AS owner,\n    pg_encoding_to_char(encoding) AS encoding, encoding AS encoding_id,\n    datcollate AS lc_collate, datctype AS lc_ctype\n    FROM pg_database JOIN pg_roles ON pg_roles.oid = pg_database.datdba\n    WHERE datname = %(db)s\n    \"\"\"\n    cursor.execute(query, {'db': db})\n    return cursor.fetchone()\n\ndef db_exists(cursor, db):\n    query = \"SELECT * FROM pg_database WHERE datname=%(db)s\"\n    cursor.execute(query, {'db': db})\n    return cursor.rowcount == 1\n\ndef db_delete(cursor, db):\n    if db_exists(cursor, db):\n        query = \"DROP DATABASE %s\" % pg_quote_identifier(db, 'database')\n        cursor.execute(query)\n        return True\n    else:\n        return False\n\ndef db_create(cursor, db, owner, template, encoding, lc_collate, lc_ctype):\n    params = dict(enc=encoding, collate=lc_collate, ctype=lc_ctype)\n    if not db_exists(cursor, db):\n        query_fragments = ['CREATE DATABASE %s' % pg_quote_identifier(db, 'database')]\n        if owner:\n            query_fragments.append('OWNER %s' % pg_quote_identifier(owner, 'role'))\n        if template:\n            query_fragments.append('TEMPLATE %s' % pg_quote_identifier(template, 'database'))\n        if encoding:\n            query_fragments.append('ENCODING %(enc)s')\n        if lc_collate:\n            query_fragments.append('LC_COLLATE %(collate)s')\n        if lc_ctype:\n            query_fragments.append('LC_CTYPE %(ctype)s')\n        query = ' '.join(query_fragments)\n        cursor.execute(query, params)\n        return True\n    else:\n        db_info = get_db_info(cursor, db)\n        if (encoding and\n            get_encoding_id(cursor, encoding) != db_info['encoding_id']):\n            raise NotSupportedError(\n                'Changing database encoding is not supported. '\n                'Current encoding: %s' % db_info['encoding']\n            )\n        elif lc_collate and lc_collate != db_info['lc_collate']:\n            raise NotSupportedError(\n                'Changing LC_COLLATE is not supported. '\n                'Current LC_COLLATE: %s' % db_info['lc_collate']\n            )\n        elif lc_ctype and lc_ctype != db_info['lc_ctype']:\n            raise NotSupportedError(\n                'Changing LC_CTYPE is not supported.'\n                'Current LC_CTYPE: %s' % db_info['lc_ctype']\n            )\n        elif owner and owner != db_info['owner']:\n            return set_owner(cursor, db, owner)\n        else:\n            return False\n\ndef db_matches(cursor, db, owner, template, encoding, lc_collate, lc_ctype):\n    if not db_exists(cursor, db):\n       return False\n    else:\n        db_info = get_db_info(cursor, db)\n        if (encoding and\n            get_encoding_id(cursor, encoding) != db_info['encoding_id']):\n            return False\n        elif lc_collate and lc_collate != db_info['lc_collate']:\n            return False\n        elif lc_ctype and lc_ctype != db_info['lc_ctype']:\n            return False\n        elif owner and owner != db_info['owner']:\n            return False\n        else:\n            return True\n\n# ===========================================\n# Module execution.\n#\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=dict(\n            login_user=dict(default=\"postgres\"),\n            login_password=dict(default=\"\"),\n            login_host=dict(default=\"\"),\n            login_unix_socket=dict(default=\"\"),\n            port=dict(default=\"5432\"),\n            db=dict(required=True, aliases=['name']),\n            owner=dict(default=\"\"),\n            template=dict(default=\"\"),\n            encoding=dict(default=\"\"),\n            lc_collate=dict(default=\"\"),\n            lc_ctype=dict(default=\"\"),\n            state=dict(default=\"present\", choices=[\"absent\", \"present\"]),\n        ),\n        supports_check_mode = True\n    )\n\n    if not postgresqldb_found:\n        module.fail_json(msg=\"the python psycopg2 module is required\")\n\n    db = module.params[\"db\"]\n    port = module.params[\"port\"]\n    owner = module.params[\"owner\"]\n    template = module.params[\"template\"]\n    encoding = module.params[\"encoding\"]\n    lc_collate = module.params[\"lc_collate\"]\n    lc_ctype = module.params[\"lc_ctype\"]\n    state = module.params[\"state\"]\n    changed = False\n\n    # To use defaults values, keyword arguments must be absent, so\n    # check which values are empty and don't include in the **kw\n    # dictionary\n    params_map = {\n        \"login_host\":\"host\",\n        \"login_user\":\"user\",\n        \"login_password\":\"password\",\n        \"port\":\"port\"\n    }\n    kw = dict( (params_map[k], v) for (k, v) in iteritems(module.params)\n              if k in params_map and v != '' )\n\n    # If a login_unix_socket is specified, incorporate it here.\n    is_localhost = \"host\" not in kw or kw[\"host\"] == \"\" or kw[\"host\"] == \"localhost\"\n    if is_localhost and module.params[\"login_unix_socket\"] != \"\":\n        kw[\"host\"] = module.params[\"login_unix_socket\"]\n\n    try:\n        db_connection = psycopg2.connect(database=\"postgres\", **kw)\n        # Enable autocommit so we can create databases\n        if psycopg2.__version__ >= '2.4.2':\n            db_connection.autocommit = True\n        else:\n            db_connection.set_isolation_level(psycopg2\n                                              .extensions\n                                              .ISOLATION_LEVEL_AUTOCOMMIT)\n        cursor = db_connection.cursor(\n                cursor_factory=psycopg2.extras.DictCursor)\n    except Exception:\n        e = get_exception()\n        module.fail_json(msg=\"unable to connect to database: %s\" % e)\n\n    try:\n        if module.check_mode:\n            if state == \"absent\":\n                changed = db_exists(cursor, db)\n            elif state == \"present\":\n                changed = not db_matches(cursor, db, owner, template, encoding,\n                                         lc_collate, lc_ctype)\n            module.exit_json(changed=changed, db=db)\n\n        if state == \"absent\":\n            try:\n                changed = db_delete(cursor, db)\n            except SQLParseError:\n                e = get_exception()\n                module.fail_json(msg=str(e))\n\n        elif state == \"present\":\n            try:\n                changed = db_create(cursor, db, owner, template, encoding,\n                                lc_collate, lc_ctype)\n            except SQLParseError:\n                e = get_exception()\n                module.fail_json(msg=str(e))\n    except NotSupportedError:\n        e = get_exception()\n        module.fail_json(msg=str(e))\n    except SystemExit:\n        # Avoid catching this on Python 2.4 \n        raise\n    except Exception:\n        e = get_exception()\n        module.fail_json(msg=\"Database query failed: %s\" % e)\n\n    module.exit_json(changed=changed, db=db)\n\n# import module snippets\nfrom ansible.module_utils.basic import *\nfrom ansible.module_utils.database import *\nif __name__ == '__main__':\n    main()\n", "path": "database/postgresql/postgresql_db.py"}]}