├── example ├── __init__.py ├── djangoappengine_rdbms ├── django ├── debugger.py ├── manage.py ├── app.yaml ├── urls.py ├── settings.py └── pip-log.txt ├── djangoappengine_rdbms ├── models.py ├── db │ ├── __init__.py │ └── backend │ │ ├── __init__.py │ │ ├── constants │ │ ├── __init__.py │ │ ├── REFRESH.py │ │ ├── FLAG.py │ │ ├── FIELD_TYPE.py │ │ ├── CLIENT.py │ │ ├── CR.py │ │ └── ER.py │ │ ├── introspection.py │ │ ├── stubs.py │ │ └── base.py ├── lib │ ├── __init__.py │ └── memcache.py ├── deferred │ ├── __init__.py │ └── handler.py ├── tests │ ├── __init__.py │ └── base.py ├── __init__.py ├── management │ ├── commands │ │ ├── __init__.py │ │ ├── remote.py │ │ ├── remote_changepassword.py │ │ ├── deploy.py │ │ └── runserver.py │ ├── __init__.py │ └── decorators.py ├── urls.py ├── templates │ └── djangoappengine_rdbms │ │ ├── commands.html │ │ └── command_details.html ├── utils.py ├── forms.py ├── settings_base.py ├── LICENSE ├── main │ ├── main.py │ └── __init__.py ├── mail.py ├── views.py ├── storage.py └── boot.py ├── example_django_1_2 ├── __init__.py ├── manage.py ├── urls.py └── settings.py ├── .gitignore ├── README └── README.textile /example/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/models.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example_django_1_2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.DS_Store 3 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/db/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/lib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/deferred/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/management/commands/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/djangoappengine_rdbms: -------------------------------------------------------------------------------- 1 | ../djangoappengine_rdbms/ -------------------------------------------------------------------------------- /djangoappengine_rdbms/management/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/lib/memcache.py: -------------------------------------------------------------------------------- 1 | from google.appengine.api.memcache import * 2 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/db/backend/__init__.py: -------------------------------------------------------------------------------- 1 | from django.db.backends.mysql import creation -------------------------------------------------------------------------------- /example/django: -------------------------------------------------------------------------------- 1 | ../../../python-virtualenv/django-1.3-python2.6/lib/python2.6/site-packages/django -------------------------------------------------------------------------------- /djangoappengine_rdbms/db/backend/constants/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['CR', 'FIELD_TYPE','CLIENT','REFRESH','ER','FLAG'] 2 | -------------------------------------------------------------------------------- /example/debugger.py: -------------------------------------------------------------------------------- 1 | def pdb(): 2 | import pdb 3 | import sys 4 | for attr in ('stdin', 'stdout', 'stderr'): 5 | setattr(sys, attr, getattr(sys, '__%s__' % attr)) 6 | 7 | return pdb -------------------------------------------------------------------------------- /djangoappengine_rdbms/db/backend/constants/REFRESH.py: -------------------------------------------------------------------------------- 1 | """MySQL REFRESH Constants 2 | 3 | These constants seem to mostly deal with things internal to the 4 | MySQL server. Forget you saw this. 5 | 6 | """ 7 | 8 | GRANT = 1 9 | LOG = 2 10 | TABLES = 4 11 | HOSTS = 8 12 | STATUS = 16 13 | THREADS = 32 14 | SLAVE = 64 15 | MASTER = 128 16 | READ_LOCK = 16384 17 | FAST = 32768 18 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/urls.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | from django.conf import settings 4 | from django.conf.urls.defaults import * 5 | 6 | from views import commands, command_details 7 | 8 | urlpatterns = patterns('', 9 | url(r'^command/$', commands, name="commands"), 10 | url(r'^command/(?P[\w\.]+)/(?P\w+)/$', command_details, name="command_details"), 11 | ) -------------------------------------------------------------------------------- /djangoappengine_rdbms/templates/djangoappengine_rdbms/commands.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n %} 3 | 4 | {% block content %} 5 | 6 |

{% trans "Command list" %}

7 | 12 | {% endblock %} -------------------------------------------------------------------------------- /djangoappengine_rdbms/db/backend/constants/FLAG.py: -------------------------------------------------------------------------------- 1 | """MySQL FLAG Constants 2 | 3 | These flags are used along with the FIELD_TYPE to indicate various 4 | properties of columns in a result set. 5 | 6 | """ 7 | 8 | NOT_NULL = 1 9 | PRI_KEY = 2 10 | UNIQUE_KEY = 4 11 | MULTIPLE_KEY = 8 12 | BLOB = 16 13 | UNSIGNED = 32 14 | ZEROFILL = 64 15 | BINARY = 128 16 | ENUM = 256 17 | AUTO_INCREMENT = 512 18 | TIMESTAMP = 1024 19 | SET = 2048 20 | NUM = 32768 21 | PART_KEY = 16384 22 | GROUP = 32768 23 | UNIQUE = 65536 24 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/management/decorators.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def redirect_stderr_stdout(stdout=sys.stdout, stderr=sys.stderr ): 4 | def wrap(f): 5 | def newf(*args, **kwargs): 6 | old_stderr, old_stdout = sys.stderr, sys.stdout 7 | sys.stderr = stderr 8 | sys.stdout = stdout 9 | try: 10 | return f(*args, **kwargs) 11 | finally: 12 | sys.stderr, sys.stdout = old_stderr, old_stdout 13 | 14 | return newf 15 | return wrap -------------------------------------------------------------------------------- /example/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from django.core.management import execute_manager 3 | try: 4 | import settings # Assumed to be in the same directory. 5 | except ImportError: 6 | import sys 7 | sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) 8 | sys.exit(1) 9 | 10 | if __name__ == "__main__": 11 | execute_manager(settings) 12 | -------------------------------------------------------------------------------- /example_django_1_2/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from django.core.management import execute_manager 3 | try: 4 | import settings # Assumed to be in the same directory. 5 | except ImportError: 6 | import sys 7 | sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) 8 | sys.exit(1) 9 | 10 | if __name__ == "__main__": 11 | execute_manager(settings) 12 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/deferred/handler.py: -------------------------------------------------------------------------------- 1 | # Initialize Django 2 | from djangoappengine_rdbms import main 3 | 4 | from django.utils.importlib import import_module 5 | from django.conf import settings 6 | 7 | # load all models.py to ensure signal handling installation or index loading 8 | # of some apps 9 | for app in settings.INSTALLED_APPS: 10 | try: 11 | import_module('%s.models' % (app)) 12 | except ImportError: 13 | pass 14 | 15 | from google.appengine.ext.deferred.handler import main 16 | from google.appengine.ext.deferred.deferred import application 17 | 18 | if __name__ == '__main__': 19 | main() 20 | -------------------------------------------------------------------------------- /example/app.yaml: -------------------------------------------------------------------------------- 1 | application: djangosqlcloud 2 | version: 1 3 | runtime: python 4 | api_version: 1 5 | 6 | builtins: 7 | - remote_api: on 8 | - appstats: on 9 | 10 | inbound_services: 11 | - warmup 12 | 13 | 14 | 15 | 16 | handlers: 17 | - url: /static 18 | static_dir: static 19 | 20 | - url: /_ah/queue/deferred 21 | script: djangoappengine_rdbms/deferred/handler.py 22 | login: admin 23 | 24 | - url: /_ah/stats/.* 25 | script: djangoappengine_rdbms/appstats/ui.py 26 | 27 | - url: /media/admin 28 | static_dir: django/contrib/admin/media 29 | expiration: '0' 30 | 31 | - url: /.* 32 | script: djangoappengine_rdbms/main/main.py 33 | -------------------------------------------------------------------------------- /example_django_1_2/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import * 2 | 3 | # Uncomment the next two lines to enable the admin: 4 | # from django.contrib import admin 5 | # admin.autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | # Example: 9 | # (r'^example_django_1_2/', include('example_django_1_2.foo.urls')), 10 | 11 | # Uncomment the admin/doc line below and add 'django.contrib.admindocs' 12 | # to INSTALLED_APPS to enable admin documentation: 13 | # (r'^admin/doc/', include('django.contrib.admindocs.urls')), 14 | 15 | # Uncomment the next line to enable the admin: 16 | # (r'^admin/', include(admin.site.urls)), 17 | ) 18 | -------------------------------------------------------------------------------- /example/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import * 2 | 3 | # Uncomment the next two lines to enable the admin: 4 | from django.contrib import admin 5 | admin.autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | # Example: 9 | # (r'^example/', include('example.foo.urls')), 10 | 11 | # Uncomment the admin/doc line below and add 'django.contrib.admindocs' 12 | # to INSTALLED_APPS to enable admin documentation: 13 | # (r'^admin/doc/', include('django.contrib.admindocs.urls')), 14 | 15 | # Uncomment the next line to enable the admin: 16 | (r'^admin/', include(admin.site.urls)), 17 | (r'^appengine/admin/', include('djangoappengine_rdbms.urls')), 18 | ) 19 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/db/backend/constants/FIELD_TYPE.py: -------------------------------------------------------------------------------- 1 | """MySQL FIELD_TYPE Constants 2 | 3 | These constants represent the various column (field) types that are 4 | supported by MySQL. 5 | 6 | """ 7 | 8 | DECIMAL = 0 9 | TINY = 1 10 | SHORT = 2 11 | LONG = 3 12 | FLOAT = 4 13 | DOUBLE = 5 14 | NULL = 6 15 | TIMESTAMP = 7 16 | LONGLONG = 8 17 | INT24 = 9 18 | DATE = 10 19 | TIME = 11 20 | DATETIME = 12 21 | YEAR = 13 22 | NEWDATE = 14 23 | VARCHAR = 15 24 | BIT = 16 25 | NEWDECIMAL = 246 26 | ENUM = 247 27 | SET = 248 28 | TINY_BLOB = 249 29 | MEDIUM_BLOB = 250 30 | LONG_BLOB = 251 31 | BLOB = 252 32 | VAR_STRING = 253 33 | STRING = 254 34 | GEOMETRY = 255 35 | 36 | CHAR = TINY 37 | INTERVAL = ENUM 38 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/db/backend/constants/CLIENT.py: -------------------------------------------------------------------------------- 1 | """MySQL CLIENT constants 2 | 3 | These constants are used when creating the connection. Use bitwise-OR 4 | (|) to combine options together, and pass them as the client_flags 5 | parameter to MySQLdb.Connection. For more information on these flags, 6 | see the MySQL C API documentation for mysql_real_connect(). 7 | 8 | """ 9 | 10 | LONG_PASSWORD = 1 11 | FOUND_ROWS = 2 12 | LONG_FLAG = 4 13 | CONNECT_WITH_DB = 8 14 | NO_SCHEMA = 16 15 | COMPRESS = 32 16 | ODBC = 64 17 | LOCAL_FILES = 128 18 | IGNORE_SPACE = 256 19 | CHANGE_USER = 512 20 | INTERACTIVE = 1024 21 | SSL = 2048 22 | IGNORE_SIGPIPE = 4096 23 | TRANSACTIONS = 8192 # mysql_com.h was WRONG prior to 3.23.35 24 | RESERVED = 16384 25 | SECURE_CONNECTION = 32768 26 | MULTI_STATEMENTS = 65536 27 | MULTI_RESULTS = 131072 28 | 29 | 30 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/db/backend/constants/CR.py: -------------------------------------------------------------------------------- 1 | """MySQL Connection Errors 2 | 3 | Nearly all of these raise OperationalError. COMMANDS_OUT_OF_SYNC 4 | raises ProgrammingError. 5 | 6 | """ 7 | 8 | MIN_ERROR = 2000 9 | MAX_ERROR = 2999 10 | UNKNOWN_ERROR = 2000 11 | SOCKET_CREATE_ERROR = 2001 12 | CONNECTION_ERROR = 2002 13 | CONN_HOST_ERROR = 2003 14 | IPSOCK_ERROR = 2004 15 | UNKNOWN_HOST = 2005 16 | SERVER_GONE_ERROR = 2006 17 | VERSION_ERROR = 2007 18 | OUT_OF_MEMORY = 2008 19 | WRONG_HOST_INFO = 2009 20 | LOCALHOST_CONNECTION = 2010 21 | TCP_CONNECTION = 2011 22 | SERVER_HANDSHAKE_ERR = 2012 23 | SERVER_LOST = 2013 24 | COMMANDS_OUT_OF_SYNC = 2014 25 | NAMEDPIPE_CONNECTION = 2015 26 | NAMEDPIPEWAIT_ERROR = 2016 27 | NAMEDPIPEOPEN_ERROR = 2017 28 | NAMEDPIPESETSTATE_ERROR = 2018 29 | CANT_READ_CHARSET = 2019 30 | NET_PACKET_TOO_LARGE = 2020 31 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/management/commands/remote.py: -------------------------------------------------------------------------------- 1 | from django.core.management import execute_from_command_line 2 | from django.core.management.base import BaseCommand 3 | 4 | class Command(BaseCommand): 5 | help = 'Runs a command with access to the remote App Engine production ' \ 6 | 'server (e.g. manage.py remote shell)' 7 | args = 'remotecommand' 8 | 9 | def run_from_argv(self, argv): 10 | import pdb; pdb.set_trace() 11 | from django.db import connections 12 | from ...db.backend.base import DatabaseWrapper 13 | from ...db.backend.stubs import stub_manager 14 | for connection in connections.all(): 15 | if isinstance(connection, DatabaseWrapper): 16 | stub_manager.setup_remote_stubs(connection) 17 | break 18 | argv = argv[:1] + argv[2:] 19 | 20 | execute_from_command_line(argv) 21 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/utils.py: -------------------------------------------------------------------------------- 1 | from google.appengine.api import apiproxy_stub_map 2 | from google.appengine.api.app_identity import get_application_id 3 | import os 4 | 5 | have_appserver = bool(apiproxy_stub_map.apiproxy.GetStub('datastore_v3')) 6 | 7 | if have_appserver: 8 | appid = get_application_id() 9 | else: 10 | try: 11 | from google.appengine.tools import dev_appserver 12 | from .boot import PROJECT_DIR 13 | appconfig = dev_appserver.LoadAppConfig(PROJECT_DIR, {}, 14 | default_partition='dev')[0] 15 | appid = appconfig.application.split('~', 1)[-1] 16 | except ImportError, e: 17 | raise Exception('Could not get appid. Is your app.yaml file missing? ' 18 | 'Error was: %s' % e) 19 | 20 | on_production_server = have_appserver and \ 21 | not os.environ.get('SERVER_SOFTWARE', '').lower().startswith('devel') 22 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | # Some options does not make sense, like pythonpath 4 | EXCLUDED_OPTIONS = ["--pythonpath","--settings","--noinput"] 5 | 6 | class CommandArgsForm(forms.Form): 7 | args = forms.CharField(required=False) 8 | 9 | 10 | @property 11 | def option_list(self): 12 | options = u"" 13 | for option in self.command.option_list: 14 | #import debugger; debugger.pdb().set_trace() 15 | if unicode(option) not in EXCLUDED_OPTIONS: 16 | options += u" " + unicode(option) 17 | 18 | return options 19 | 20 | def __init__(self,*args,**kwargs): 21 | #import debugger; debugger.pdb().set_trace() 22 | if "command" in kwargs: 23 | self.command = kwargs["command"] 24 | del kwargs["command"] 25 | 26 | super(CommandArgsForm,self).__init__(*args,**kwargs) 27 | 28 | if self.command: 29 | self.fields['args'].help_text = self.option_list 30 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/tests/base.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.core.management import call_command 3 | from django.test.testcases import TestCase as BaseTestCasea 4 | from django.db.models import loading 5 | 6 | class TestCase(TestCase): 7 | ''' 8 | Adds apps specified in `self.apps` to `INSTALLED_APPS` and 9 | performs a `syncdb` at runtime. 10 | ''' 11 | 12 | apps = () 13 | _source_installed_apps = () 14 | 15 | def _pre_setup(self): 16 | super(AppTestCase, self)._pre_setup() 17 | 18 | if self.apps: 19 | self._source_installed_apps = settings.INSTALLED_APPS 20 | settings.INSTALLED_APPS = settings.INSTALLED_APPS + self.apps 21 | loading.cache.loaded = False 22 | call_command('syncdb', verbosity=0) 23 | 24 | def _post_teardown(self): 25 | super(AppTestCase, self)._post_teardown() 26 | 27 | if self._source_installed_apps: 28 | settings.INSTALLED_APPS = self._source_installed_apps 29 | self._source_installed_apps = () 30 | loading.cache.loaded = False -------------------------------------------------------------------------------- /djangoappengine_rdbms/templates/djangoappengine_rdbms/command_details.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n %} 3 | 4 | {% block breadcrumbs %} 5 | 14 | {% endblock %} 15 | 16 | {% block content %} 17 | 18 |

{{ app_name }} {{ command_name }}

19 | 20 |

21 | {{ command.help }} 22 |

23 | 24 | 25 | 26 |
27 |
    28 | {{ form.as_ul }} 29 |
30 | 31 | 32 | 33 |
34 | 35 | 36 | {% if stdout %} 37 | 38 |

Command output

39 | 40 |
41 | {{ stdout }}
42 | 	
43 | 44 | {% endif %} 45 | 46 | 47 | {% if stderr %} 48 | 49 |

Command errors

50 | 51 |
52 | {{ stderr }}
53 | 	
54 | 55 | {% endif %} 56 | 57 | {% endblock %} -------------------------------------------------------------------------------- /djangoappengine_rdbms/management/commands/remote_changepassword.py: -------------------------------------------------------------------------------- 1 | from django.core.management.base import BaseCommand, CommandError 2 | from django.contrib.auth.models import User 3 | from optparse import make_option 4 | 5 | class Command(BaseCommand): 6 | 7 | option_list = BaseCommand.option_list + ( 8 | make_option('--username', dest='username', default=None, help='Specifies the username for the superuser.'), 9 | make_option('--password', dest='password', default=None, help='Specifies the email address for the superuser.'), 10 | ) 11 | 12 | help = "Change a user's password for django.contrib.auth." 13 | 14 | requires_model_validation = False 15 | 16 | 17 | def handle(self, *args, **options): 18 | 19 | try: 20 | u = User.objects.get(username=options['username']) 21 | except User.DoesNotExist: 22 | raise CommandError("user '%s' does not exist" % options['username']) 23 | 24 | print "Changing password for user '%s'" % u.username 25 | 26 | 27 | 28 | u.set_password(options['password']) 29 | u.save() 30 | 31 | return "Password changed successfully for user '%s'" % u.username 32 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Just Started - Just a Draft. 2 | It is almost working. 3 | DO NOT USE!! 4 | 5 | Toolkit for use django with Google Cloud SQL in AppEngine 6 | 7 | This project is inspired (forked) in the very google djangoappengine project. 8 | 9 | INSTALATION: 10 | Basicaly setup a basic django project 11 | copy or synlink the djangoappengine_rdbms to the root of your project. 12 | You should not install or put these files in the path beacuse they need to deployed to 13 | appengine. 14 | add the following line to your settings 15 | 16 | from djangoappengine_rdbms.settings_base import * 17 | 18 | and configure you database. 19 | 20 | DATABASES = { 21 | 'default': { 22 | 'ENGINE': 'djangoappengine_rdbms.db.backend', 23 | 'INSTANCE': 'djangosqlcloudmysql:example', 24 | 'NAME': 'example', # Or path to database file if using sqlite3. 25 | 'USER': 'root', # Not used with sqlite3. 26 | 'PASSWORD': 'root', 27 | } 28 | } 29 | 30 | 31 | TODO: 32 | Make remote commands work - Google Cloud SQL does not use the stub services. 33 | Strategy: Access the directely the instance like the command line tool provided by Google 34 | 35 | TODO: write better instalations intructions 36 | 37 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/settings_base.py: -------------------------------------------------------------------------------- 1 | # Initialize App Engine SDK if necessary 2 | try: 3 | from google.appengine.api import apiproxy_stub_map 4 | except ImportError: 5 | from .boot import setup_env 6 | setup_env() 7 | 8 | from djangoappengine_rdbms.utils import on_production_server, have_appserver 9 | 10 | DEBUG = not on_production_server 11 | TEMPLATE_DEBUG = DEBUG 12 | 13 | ROOT_URLCONF = 'urls' 14 | 15 | if on_production_server: 16 | EMAIL_BACKEND = 'djangoappengine_rdbms.mail.AsyncEmailBackend' 17 | else: 18 | EMAIL_BACKEND = 'djangoappengine_rdbms.mail.EmailBackend' 19 | 20 | # Specify a queue name for the async. email backend 21 | EMAIL_QUEUE_NAME = 'default' 22 | 23 | PREPARE_UPLOAD_BACKEND = 'djangoappengine_rdbms.storage.prepare_upload' 24 | SERVE_FILE_BACKEND = 'djangoappengine_rdbms.storage.serve_file' 25 | DEFAULT_FILE_STORAGE = 'djangoappengine_rdbms.storage.BlobstoreStorage' 26 | FILE_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 27 | FILE_UPLOAD_HANDLERS = ( 28 | 'djangoappengine_rdbms.storage.BlobstoreFileUploadHandler', 29 | 'django.core.files.uploadhandler.MemoryFileUploadHandler', 30 | ) 31 | 32 | CACHES = { 33 | 'default': { 34 | 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 35 | 'TIMEOUT': 0, 36 | } 37 | } 38 | 39 | SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' 40 | 41 | if not on_production_server: 42 | INTERNAL_IPS = ('127.0.0.1',) 43 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Tomas Correa, Sandro Salles and all contributors. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of All Buttons Pressed nor 15 | the names of its contributors may be used to endorse or promote products 16 | derived from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /djangoappengine_rdbms/management/commands/deploy.py: -------------------------------------------------------------------------------- 1 | from ...boot import PROJECT_DIR 2 | from ...utils import appconfig 3 | from django.conf import settings 4 | from django.core.management import call_command 5 | from django.core.management.base import BaseCommand 6 | import logging 7 | import sys 8 | import time 9 | 10 | PRE_DEPLOY_COMMANDS = () 11 | if 'mediagenerator' in settings.INSTALLED_APPS: 12 | PRE_DEPLOY_COMMANDS += ('generatemedia',) 13 | PRE_DEPLOY_COMMANDS = getattr(settings, 'PRE_DEPLOY_COMMANDS', 14 | PRE_DEPLOY_COMMANDS) 15 | POST_DEPLOY_COMMANDS = getattr(settings, 'POST_DEPLOY_COMMANDS', ()) 16 | 17 | def run_appcfg(argv): 18 | # We don't really want to use that one though, it just executes this one 19 | from google.appengine.tools import appcfg 20 | 21 | # Reset the logging level to WARN as appcfg will spew tons of logs on INFO 22 | logging.getLogger().setLevel(logging.WARN) 23 | 24 | new_args = argv[:] 25 | new_args[1] = 'update' 26 | if appconfig.runtime != 'python': 27 | new_args.insert(1, '-R') 28 | new_args.append(PROJECT_DIR) 29 | syncdb = True 30 | if '--nosyncdb' in new_args: 31 | syncdb = False 32 | new_args.remove('--nosyncdb') 33 | appcfg.main(new_args) 34 | 35 | if syncdb: 36 | print 'Running syncdb.' 37 | # Wait a little bit for deployment to finish 38 | for countdown in range(9, 0, -1): 39 | sys.stdout.write('%s\r' % countdown) 40 | time.sleep(1) 41 | from django.db import connections 42 | for connection in connections.all(): 43 | if hasattr(connection, 'setup_remote'): 44 | connection.setup_remote() 45 | call_command('syncdb', remote=True, interactive=True) 46 | 47 | if getattr(settings, 'ENABLE_PROFILER', False): 48 | print '--------------------------\n' \ 49 | 'WARNING: PROFILER ENABLED!\n' \ 50 | '--------------------------' 51 | 52 | class Command(BaseCommand): 53 | """Deploys the website to the production server. 54 | 55 | Any additional arguments are passed directly to appcfg.py update 56 | """ 57 | help = 'Calls appcfg.py update for the current project.' 58 | args = '[any appcfg.py options]' 59 | 60 | def run_from_argv(self, argv): 61 | for command in PRE_DEPLOY_COMMANDS: 62 | call_command(command) 63 | try: 64 | run_appcfg(argv) 65 | finally: 66 | for command in POST_DEPLOY_COMMANDS: 67 | call_command(command) 68 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/main/main.py: -------------------------------------------------------------------------------- 1 | # Python 2.5 CGI handler 2 | import os 3 | import sys 4 | 5 | from djangoappengine_rdbms.main import application 6 | from google.appengine.ext.webapp.util import run_wsgi_app 7 | 8 | from djangoappengine_rdbms.boot import setup_logging, env_ext 9 | from django.conf import settings 10 | 11 | path_backup = None 12 | 13 | def real_main(): 14 | # Reset path and environment variables 15 | global path_backup 16 | try: 17 | sys.path = path_backup[:] 18 | except: 19 | path_backup = sys.path[:] 20 | os.environ.update(env_ext) 21 | setup_logging() 22 | 23 | # Run the WSGI CGI handler with that application. 24 | run_wsgi_app(application) 25 | 26 | def profile_main(func): 27 | from cStringIO import StringIO 28 | import cProfile 29 | import logging 30 | import pstats 31 | import random 32 | only_forced_profile = getattr(settings, 'ONLY_FORCED_PROFILE', False) 33 | profile_percentage = getattr(settings, 'PROFILE_PERCENTAGE', None) 34 | if (only_forced_profile and 35 | 'profile=forced' not in os.environ.get('QUERY_STRING')) or \ 36 | (not only_forced_profile and profile_percentage and 37 | float(profile_percentage) / 100.0 <= random.random()): 38 | return func() 39 | 40 | prof = cProfile.Profile() 41 | prof = prof.runctx('func()', globals(), locals()) 42 | stream = StringIO() 43 | stats = pstats.Stats(prof, stream=stream) 44 | sort_by = getattr(settings, 'SORT_PROFILE_RESULTS_BY', 'time') 45 | if not isinstance(sort_by, (list, tuple)): 46 | sort_by = (sort_by,) 47 | stats.sort_stats(*sort_by) 48 | 49 | restrictions = [] 50 | profile_pattern = getattr(settings, 'PROFILE_PATTERN', None) 51 | if profile_pattern: 52 | restrictions.append(profile_pattern) 53 | max_results = getattr(settings, 'MAX_PROFILE_RESULTS', 80) 54 | if max_results and max_results != 'all': 55 | restrictions.append(max_results) 56 | stats.print_stats(*restrictions) 57 | extra_output = getattr(settings, 'EXTRA_PROFILE_OUTPUT', None) or () 58 | if not isinstance(sort_by, (list, tuple)): 59 | extra_output = (extra_output,) 60 | if 'callees' in extra_output: 61 | stats.print_callees() 62 | if 'callers' in extra_output: 63 | stats.print_callers() 64 | logging.info('Profile data:\n%s', stream.getvalue()) 65 | 66 | def make_profileable(func): 67 | if getattr(settings, 'ENABLE_PROFILER', False): 68 | return lambda: profile_main(func) 69 | return func 70 | 71 | main = make_profileable(real_main) 72 | 73 | if __name__ == '__main__': 74 | main() 75 | -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h1. djangoappengine_rbdms 2 | 3 | 4 | This is a toolkit to run native django code with admin in the Google AppEngine. 5 | This project is inspired (forked) in the very google djangoappengine project. I based many code and modules 6 | in that project. 7 | 8 | h2. WARNINGS 9 | 10 | It is working with some limitations, it is not tested and I'm NOT using it. 11 | The remote command is not working at all. 12 | DO NOT USE IT IN PRODUCTION. 13 | 14 | 15 | h2. PREREQUISITES 16 | 17 | # GAE Instance created 18 | # Google SQL Cloud instance created 19 | # GAE SDK 1.6 instaled and working 20 | 21 | h2. INSTALATION: 22 | 23 | This instalation does not include the django instalation, or GAE SDK instalation. 24 | Basicaly setup a basic django project, 25 | 26 | pre. django-admin.py starproject example 27 | 28 | and copy or synlink the djangoappengine_rdbms to the root of your project. 29 | You should not install or put these files in the path beacuse they need to deployed to 30 | appengine. You can also checkout the example project 31 | 32 | 33 | h2. SETUP: 34 | 35 | add the following line to your settings 36 | 37 | pre. from djangoappengine_rdbms.settings_base import * 38 | 39 | and configure you database. 40 | 41 | pre. DATABASES = { 42 | 'default': { 43 | 'ENGINE': 'djangoappengine_rdbms.db.backend', 44 | 'INSTANCE': 'djangosqlcloudmysql:example', 45 | 'NAME': 'example', # Or path to database file if using sqlite3. 46 | 'USER': 'root', # Not used with sqlite3. 47 | 'PASSWORD': 'root', 48 | } 49 | } 50 | 51 | h2. RUNNING: 52 | 53 | Just run the default runserver django command 54 | 55 | pre. ./manage.py runserver 56 | 57 | 58 | h2. DEPLOY: 59 | 60 | pre. ./manage.py deploy 61 | 62 | As long as the remote command is not working I used the command line tool provide by Google to 63 | setup up the DB. 64 | 65 | h2. TODO: 66 | 67 | # Make remote commands work - Google Cloud SQL does not use the stub services. Strategy: Access the directely the instance like the command line tool provided by Google 68 | # Write better instalations intructions. 69 | # Test, test, test 70 | 71 | h2. GAMBIARRA (a portugues word that means something like a "quick fix"): 72 | 73 | It is not possible yet (I hope) to access the Google Cloud SQL via stub infra-structures, 74 | só a I plan adpat the http://shell.appspot.com/ to django shell insted of a python shell. 75 | 76 | h2. GAMBIARRA 2 - webaccess to django manage.py commands 77 | 78 | add the following line to your urls in urls.py to access the manage.py commands. 79 | 80 | pre. (r'^appengine/admin/', include('djangoappengine_rdbms.urls')), 81 | 82 | 83 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/main/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | # Add parent folder to sys.path, so we can import boot. 5 | # App Engine causes main.py to be reloaded if an exception gets raised 6 | # on the first request of a main.py instance, so don't add project_dir multiple 7 | # times. 8 | project_dir = os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) 9 | if project_dir not in sys.path or sys.path.index(project_dir) > 0: 10 | while project_dir in sys.path: 11 | sys.path.remove(project_dir) 12 | sys.path.insert(0, project_dir) 13 | 14 | for path in sys.path[:]: 15 | if path != project_dir and os.path.isdir(os.path.join(path, 'django')): 16 | sys.path.remove(path) 17 | break 18 | 19 | # Remove the standard version of Django. 20 | if 'django' in sys.modules and sys.modules['django'].VERSION < (1, 2): 21 | for k in [k for k in sys.modules 22 | if k.startswith('django.') or k == 'django']: 23 | del sys.modules[k] 24 | 25 | from djangoappengine_rdbms.boot import setup_env 26 | setup_env() 27 | 28 | def validate_models(): 29 | """Since BaseRunserverCommand is only run once, we need to call 30 | model valdidation here to ensure it is run every time the code 31 | changes. 32 | 33 | """ 34 | import logging 35 | from django.core.management.validation import get_validation_errors 36 | try: 37 | from cStringIO import StringIO 38 | except ImportError: 39 | from StringIO import StringIO 40 | 41 | logging.info("Validating models...") 42 | 43 | s = StringIO() 44 | num_errors = get_validation_errors(s, None) 45 | 46 | if num_errors: 47 | s.seek(0) 48 | error_text = s.read() 49 | logging.critical("One or more models did not validate:\n%s" % error_text) 50 | else: 51 | logging.info("All models validated.") 52 | 53 | from djangoappengine_rdbms.utils import on_production_server 54 | if not on_production_server: 55 | validate_models() 56 | 57 | from django.core.handlers.wsgi import WSGIHandler 58 | from google.appengine.ext.webapp.util import run_wsgi_app 59 | from django.conf import settings 60 | 61 | def log_traceback(*args, **kwargs): 62 | import logging 63 | logging.exception('Exception in request:') 64 | 65 | from django.core import signals 66 | signals.got_request_exception.connect(log_traceback) 67 | 68 | # Create a Django application for WSGI 69 | application = WSGIHandler() 70 | 71 | # Add the staticfiles handler if necessary 72 | if settings.DEBUG and 'django.contrib.staticfiles' in settings.INSTALLED_APPS: 73 | from django.contrib.staticfiles.handlers import StaticFilesHandler 74 | application = StaticFilesHandler(application) 75 | 76 | if getattr(settings, 'ENABLE_APPSTATS', False): 77 | from google.appengine.ext.appstats.recording import appstats_wsgi_middleware 78 | application = appstats_wsgi_middleware(application) 79 | -------------------------------------------------------------------------------- /example/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for example project. 2 | 3 | from djangoappengine_rdbms.settings_base import * 4 | 5 | DEBUG = True 6 | TEMPLATE_DEBUG = DEBUG 7 | 8 | ADMINS = ( 9 | # ('Your Name', 'your_email@domain.com'), 10 | ) 11 | 12 | MANAGERS = ADMINS 13 | 14 | DATABASES = { 15 | 'default': { 16 | 'ENGINE': 'djangoappengine_rdbms.db.backend', 17 | 'INSTANCE': 'djangosqlcloudmysql:example', 18 | 'NAME': 'example', # Or path to database file if using sqlite3. 19 | 'USER': 'root', # Not used with sqlite3. 20 | 'PASSWORD': 'root', 21 | } 22 | } 23 | 24 | 25 | 26 | # Local time zone for this installation. Choices can be found here: 27 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 28 | # although not all choices may be available on all operating systems. 29 | # If running in a Windows environment this must be set to the same as your 30 | # system time zone. 31 | TIME_ZONE = 'America/Chicago' 32 | 33 | # Language code for this installation. All choices can be found here: 34 | # http://www.i18nguy.com/unicode/language-identifiers.html 35 | LANGUAGE_CODE = 'en-us' 36 | 37 | SITE_ID = 1 38 | 39 | # If you set this to False, Django will make some optimizations so as not 40 | # to load the internationalization machinery. 41 | USE_I18N = True 42 | 43 | # Absolute path to the directory that holds media. 44 | # Example: "/home/media/media.lawrence.com/" 45 | MEDIA_ROOT = '' 46 | 47 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 48 | # trailing slash if there is a path component (optional in other cases). 49 | # Examples: "http://media.lawrence.com", "http://example.com/media/" 50 | MEDIA_URL = '' 51 | 52 | # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a 53 | # trailing slash. 54 | # Examples: "http://foo.com/media/", "/media/". 55 | ADMIN_MEDIA_PREFIX = '/media/admin/' 56 | 57 | # Make this unique, and don't share it with anybody. 58 | SECRET_KEY = 'w89xat6&=s-r-9*)%#b!r5ul=v&7y1%e4cj=$a^-@rkgk6__v3' 59 | 60 | # List of callables that know how to import templates from various sources. 61 | TEMPLATE_LOADERS = ( 62 | 'django.template.loaders.filesystem.load_template_source', 63 | 'django.template.loaders.app_directories.load_template_source', 64 | # 'django.template.loaders.eggs.load_template_source', 65 | ) 66 | 67 | MIDDLEWARE_CLASSES = ( 68 | 'django.middleware.common.CommonMiddleware', 69 | 'django.contrib.sessions.middleware.SessionMiddleware', 70 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 71 | ) 72 | 73 | ROOT_URLCONF = 'urls' 74 | 75 | TEMPLATE_DIRS = ( 76 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 77 | # Always use forward slashes, even on Windows. 78 | # Don't forget to use absolute paths, not relative paths. 79 | ) 80 | 81 | INSTALLED_APPS = ( 82 | 'djangoappengine_rdbms', 83 | 'django.contrib.auth', 84 | 'django.contrib.contenttypes', 85 | 'django.contrib.sessions', 86 | 'django.contrib.sites', 87 | 'django.contrib.admin', 88 | ) 89 | -------------------------------------------------------------------------------- /example_django_1_2/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for example_django_1_2 project. 2 | 3 | DEBUG = True 4 | TEMPLATE_DEBUG = DEBUG 5 | 6 | ADMINS = ( 7 | # ('Your Name', 'your_email@domain.com'), 8 | ) 9 | 10 | MANAGERS = ADMINS 11 | 12 | DATABASE_ENGINE = '' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. 13 | DATABASE_NAME = '' # Or path to database file if using sqlite3. 14 | DATABASE_USER = '' # Not used with sqlite3. 15 | DATABASE_PASSWORD = '' # Not used with sqlite3. 16 | DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. 17 | DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. 18 | 19 | # Local time zone for this installation. Choices can be found here: 20 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 21 | # although not all choices may be available on all operating systems. 22 | # If running in a Windows environment this must be set to the same as your 23 | # system time zone. 24 | TIME_ZONE = 'America/Chicago' 25 | 26 | # Language code for this installation. All choices can be found here: 27 | # http://www.i18nguy.com/unicode/language-identifiers.html 28 | LANGUAGE_CODE = 'en-us' 29 | 30 | SITE_ID = 1 31 | 32 | # If you set this to False, Django will make some optimizations so as not 33 | # to load the internationalization machinery. 34 | USE_I18N = True 35 | 36 | # Absolute path to the directory that holds media. 37 | # Example: "/home/media/media.lawrence.com/" 38 | MEDIA_ROOT = '' 39 | 40 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 41 | # trailing slash if there is a path component (optional in other cases). 42 | # Examples: "http://media.lawrence.com", "http://example.com/media/" 43 | MEDIA_URL = '' 44 | 45 | # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a 46 | # trailing slash. 47 | # Examples: "http://foo.com/media/", "/media/". 48 | ADMIN_MEDIA_PREFIX = '/media/' 49 | 50 | # Make this unique, and don't share it with anybody. 51 | SECRET_KEY = 'u5+6(uk5fv&%(o261shn!$tx_xjia3c)%ml4@zukf^c=*t_8p&' 52 | 53 | # List of callables that know how to import templates from various sources. 54 | TEMPLATE_LOADERS = ( 55 | 'django.template.loaders.filesystem.load_template_source', 56 | 'django.template.loaders.app_directories.load_template_source', 57 | # 'django.template.loaders.eggs.load_template_source', 58 | ) 59 | 60 | MIDDLEWARE_CLASSES = ( 61 | 'django.middleware.common.CommonMiddleware', 62 | 'django.contrib.sessions.middleware.SessionMiddleware', 63 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 64 | ) 65 | 66 | ROOT_URLCONF = 'example_django_1_2.urls' 67 | 68 | TEMPLATE_DIRS = ( 69 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 70 | # Always use forward slashes, even on Windows. 71 | # Don't forget to use absolute paths, not relative paths. 72 | ) 73 | 74 | INSTALLED_APPS = ( 75 | 'django.contrib.auth', 76 | 'django.contrib.contenttypes', 77 | 'django.contrib.sessions', 78 | 'django.contrib.sites', 79 | ) 80 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/mail.py: -------------------------------------------------------------------------------- 1 | from email.MIMEBase import MIMEBase 2 | from django.core.mail.backends.base import BaseEmailBackend 3 | from django.core.mail import EmailMultiAlternatives 4 | from django.core.exceptions import ImproperlyConfigured 5 | from google.appengine.api import mail as aeemail 6 | from google.appengine.runtime import apiproxy_errors 7 | 8 | def _send_deferred(message, fail_silently=False): 9 | try: 10 | message.send() 11 | except (aeemail.Error, apiproxy_errors.Error): 12 | if not fail_silently: 13 | raise 14 | 15 | class EmailBackend(BaseEmailBackend): 16 | can_defer = False 17 | 18 | def send_messages(self, email_messages): 19 | num_sent = 0 20 | for message in email_messages: 21 | if self._send(message): 22 | num_sent += 1 23 | return num_sent 24 | 25 | def _copy_message(self, message): 26 | """Create and return App Engine EmailMessage class from message.""" 27 | gmsg = aeemail.EmailMessage(sender=message.from_email, 28 | to=message.to, 29 | subject=message.subject, 30 | body=message.body) 31 | if message.extra_headers.get('Reply-To', None): 32 | gmsg.reply_to = message.extra_headers['Reply-To'] 33 | if message.cc: 34 | gmsg.cc = list(message.cc) 35 | if message.bcc: 36 | gmsg.bcc = list(message.bcc) 37 | if message.attachments: 38 | # Must be populated with (filename, filecontents) tuples 39 | attachments = [] 40 | for attachment in message.attachments: 41 | if isinstance(attachment, MIMEBase): 42 | attachments.append((attachment.get_filename(), 43 | attachment.get_payload(decode=True))) 44 | else: 45 | attachments.append((attachment[0], attachment[1])) 46 | gmsg.attachments = attachments 47 | # Look for HTML alternative content 48 | if isinstance(message, EmailMultiAlternatives): 49 | for content, mimetype in message.alternatives: 50 | if mimetype == 'text/html': 51 | gmsg.html = content 52 | break 53 | return gmsg 54 | 55 | def _send(self, message): 56 | try: 57 | message = self._copy_message(message) 58 | except (ValueError, aeemail.InvalidEmailError), err: 59 | import logging 60 | logging.warn(err) 61 | if not self.fail_silently: 62 | raise 63 | return False 64 | if self.can_defer: 65 | self._defer_message(message) 66 | return True 67 | try: 68 | message.send() 69 | except (aeemail.Error, apiproxy_errors.Error): 70 | if not self.fail_silently: 71 | raise 72 | return False 73 | return True 74 | 75 | def _defer_message(self, message): 76 | from google.appengine.ext import deferred 77 | from django.conf import settings 78 | queue_name = getattr(settings, 'EMAIL_QUEUE_NAME', 'default') 79 | deferred.defer(_send_deferred, 80 | message, 81 | fail_silently=self.fail_silently, 82 | _queue=queue_name) 83 | 84 | class AsyncEmailBackend(EmailBackend): 85 | can_defer = True 86 | -------------------------------------------------------------------------------- /example/pip-log.txt: -------------------------------------------------------------------------------- 1 | Downloading/unpacking mysqldb 2 | Getting page http://pypi.python.org/simple/mysqldb 3 | Could not fetch URL http://pypi.python.org/simple/mysqldb: HTTP Error 404: Not Found (MySQLdb does not have any releases) 4 | Will skip URL http://pypi.python.org/simple/mysqldb when looking for download links for mysqldb 5 | Getting page http://pypi.python.org/simple/ 6 | Real name of requirement mysqldb is MySQLdb 7 | URLs to search for versions for mysqldb: 8 | * http://pypi.python.org/simple/MySQLdb/ 9 | Getting page http://pypi.python.org/simple/MySQLdb/ 10 | Could not fetch URL http://pypi.python.org/simple/MySQLdb/: HTTP Error 404: Not Found (MySQLdb does not have any releases) 11 | Will skip URL http://pypi.python.org/simple/MySQLdb/ when looking for download links for mysqldb 12 | Could not find any downloads that satisfy the requirement mysqldb 13 | No distributions at all found for mysqldb 14 | Exception information: 15 | Traceback (most recent call last): 16 | File "/home/tomas/python-virtualenv/appengine/lib/python2.5/site-packages/pip-0.6.3-py2.5.egg/pip/basecommand.py", line 115, in main 17 | self.run(options, args) 18 | File "/home/tomas/python-virtualenv/appengine/lib/python2.5/site-packages/pip-0.6.3-py2.5.egg/pip/commands/install.py", line 155, in run 19 | requirement_set.install_files(finder, force_root_egg_info=self.bundle, bundle=self.bundle) 20 | File "/home/tomas/python-virtualenv/appengine/lib/python2.5/site-packages/pip-0.6.3-py2.5.egg/pip/req.py", line 823, in install_files 21 | url = finder.find_requirement(req_to_install, upgrade=self.upgrade) 22 | File "/home/tomas/python-virtualenv/appengine/lib/python2.5/site-packages/pip-0.6.3-py2.5.egg/pip/index.py", line 117, in find_requirement 23 | raise DistributionNotFound('No distributions at all found for %s' % req) 24 | DistributionNotFound: No distributions at all found for mysqldb 25 | ------------------------------------------------------------ 26 | /home/tomas/python-virtualenv/appengine/bin/pip run on Sat Nov 12 13:24:56 2011 27 | Downloading/unpacking MySQLdb 28 | Getting page http://pypi.python.org/simple/MySQLdb 29 | Could not fetch URL http://pypi.python.org/simple/MySQLdb: HTTP Error 404: Not Found (MySQLdb does not have any releases) 30 | Will skip URL http://pypi.python.org/simple/MySQLdb when looking for download links for MySQLdb 31 | Getting page http://pypi.python.org/simple/ 32 | Real name of requirement MySQLdb is MySQLdb 33 | URLs to search for versions for MySQLdb: 34 | * http://pypi.python.org/simple/MySQLdb/ 35 | Getting page http://pypi.python.org/simple/MySQLdb/ 36 | Could not fetch URL http://pypi.python.org/simple/MySQLdb/: HTTP Error 404: Not Found (MySQLdb does not have any releases) 37 | Will skip URL http://pypi.python.org/simple/MySQLdb/ when looking for download links for MySQLdb 38 | Could not find any downloads that satisfy the requirement MySQLdb 39 | No distributions at all found for MySQLdb 40 | Exception information: 41 | Traceback (most recent call last): 42 | File "/home/tomas/python-virtualenv/appengine/lib/python2.5/site-packages/pip-0.6.3-py2.5.egg/pip/basecommand.py", line 115, in main 43 | self.run(options, args) 44 | File "/home/tomas/python-virtualenv/appengine/lib/python2.5/site-packages/pip-0.6.3-py2.5.egg/pip/commands/install.py", line 155, in run 45 | requirement_set.install_files(finder, force_root_egg_info=self.bundle, bundle=self.bundle) 46 | File "/home/tomas/python-virtualenv/appengine/lib/python2.5/site-packages/pip-0.6.3-py2.5.egg/pip/req.py", line 823, in install_files 47 | url = finder.find_requirement(req_to_install, upgrade=self.upgrade) 48 | File "/home/tomas/python-virtualenv/appengine/lib/python2.5/site-packages/pip-0.6.3-py2.5.egg/pip/index.py", line 117, in find_requirement 49 | raise DistributionNotFound('No distributions at all found for %s' % req) 50 | DistributionNotFound: No distributions at all found for MySQLdb 51 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/views.py: -------------------------------------------------------------------------------- 1 | from django.core.management import find_management_module, find_commands, load_command_class 2 | from django.core.management.base import handle_default_options 3 | from django.conf import settings 4 | from django.http import HttpResponse, Http404, HttpResponsePermanentRedirect, HttpResponseRedirect 5 | 6 | from django.template import Context, loader, RequestContext 7 | from forms import CommandArgsForm 8 | import StringIO 9 | from management.decorators import redirect_stderr_stdout 10 | import sys 11 | from utils import on_production_server 12 | from django.http import Http404 13 | from django.core.urlresolvers import reverse 14 | from django.utils.functional import wraps 15 | 16 | # Some commands need to be excludes beacause I can not implement those or does no make sense like run server 17 | EXCLUDED_COMMANDS = ['runserver','deploy','remote','dbshell','startapp','startproject','compilemessages','runfcgi','shell','makemessages'] 18 | 19 | OVERWRITE_COMMANDS = ['django.contrib.auth:changepassword',] 20 | 21 | 22 | def only_admin(view): 23 | 24 | @wraps(view) 25 | def inner(*args, **kwargs): 26 | if on_production_server: 27 | from google.appengine.api import users 28 | if not users.get_current_user(): 29 | return HttpResponseRedirect(users.create_login_url(reverse("commands"))) 30 | else: 31 | if users.is_current_user_admin(): 32 | return view(*args, **kwargs) 33 | 34 | raise Http404("User is not admin") 35 | else: 36 | return view(*args, **kwargs) 37 | 38 | return inner 39 | 40 | 41 | @only_admin 42 | def commands(request): 43 | 44 | 45 | template = loader.get_template('djangoappengine_rdbms/commands.html') 46 | 47 | _commands = {} 48 | #import debugger; debugger.pdb().set_trace() 49 | for app_name in settings.INSTALLED_APPS + ["django.core"]: 50 | try: 51 | command_names = find_commands(find_management_module(app_name)) 52 | for command_name in command_names: 53 | if command_name not in EXCLUDED_COMMANDS: 54 | if "%s:%s" % (app_name, command_name) not in OVERWRITE_COMMANDS: 55 | _commands[command_name] = {'command_name':command_name,'app_name':app_name} 56 | except ImportError: 57 | pass 58 | 59 | #import debugger; debugger.pdb().set_trace() 60 | 61 | _commands = _commands.values() 62 | _commands.sort(key=lambda x: x['command_name']) 63 | context = {'commands':_commands} 64 | return HttpResponse(template.render(RequestContext(request,context))) 65 | 66 | 67 | @only_admin 68 | def command_details(request, app_name, command_name): 69 | 70 | command = load_command_class(app_name, command_name) 71 | template = loader.get_template('djangoappengine_rdbms/command_details.html') 72 | # 73 | 74 | stdout = StringIO.StringIO() 75 | stderr = StringIO.StringIO() 76 | 77 | 78 | 79 | 80 | @redirect_stderr_stdout(stdout=stdout,stderr=stderr) 81 | def _execute_command(command, command_name, stdout, stderr, argv): 82 | 83 | parser = command.create_parser("manage.py", command_name) 84 | options, argss = parser.parse_args(argv.split()) 85 | handle_default_options(options) 86 | options.__dict__["stdout"] = stdout 87 | options.__dict__["stderr"] = stderr 88 | options.__dict__['interactive'] = False 89 | #import debugger; debugger.pdb().set_trace() 90 | try: 91 | return command.execute(*argss, **options.__dict__) 92 | except SystemExit, e: 93 | pass 94 | except Exception, e: 95 | stderr.write(e) 96 | 97 | 98 | 99 | 100 | if request.POST: 101 | form = CommandArgsForm(request.POST, command=command) 102 | if form.is_valid(): 103 | ret = _execute_command(command, command_name, stdout=stdout, stderr=stderr, argv = form.cleaned_data.get("args")) 104 | 105 | else: 106 | form = CommandArgsForm(command=command) 107 | 108 | stdout.seek(0) 109 | stderr.seek(0) 110 | #import debugger; debugger.pdb().set_trace() 111 | context = { 'command':command, 112 | 'command_name':command_name, 113 | 'app_name':app_name, 114 | 'form':form, 115 | 'stdout':stdout.read(), 116 | 'stderr':stderr.read(), 117 | } 118 | return HttpResponse(template.render(RequestContext(request,context))) -------------------------------------------------------------------------------- /djangoappengine_rdbms/db/backend/introspection.py: -------------------------------------------------------------------------------- 1 | from django.db.backends import BaseDatabaseIntrospection 2 | from constants import FIELD_TYPE 3 | import re 4 | 5 | foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") 6 | 7 | 8 | class DatabaseIntrospection(BaseDatabaseIntrospection): 9 | data_types_reverse = { 10 | FIELD_TYPE.BLOB: 'TextField', 11 | FIELD_TYPE.CHAR: 'CharField', 12 | FIELD_TYPE.DECIMAL: 'DecimalField', 13 | FIELD_TYPE.NEWDECIMAL: 'DecimalField', 14 | FIELD_TYPE.DATE: 'DateField', 15 | FIELD_TYPE.DATETIME: 'DateTimeField', 16 | FIELD_TYPE.DOUBLE: 'FloatField', 17 | FIELD_TYPE.FLOAT: 'FloatField', 18 | FIELD_TYPE.INT24: 'IntegerField', 19 | FIELD_TYPE.LONG: 'IntegerField', 20 | FIELD_TYPE.LONGLONG: 'BigIntegerField', 21 | FIELD_TYPE.SHORT: 'IntegerField', 22 | FIELD_TYPE.STRING: 'CharField', 23 | FIELD_TYPE.TIMESTAMP: 'DateTimeField', 24 | FIELD_TYPE.TINY: 'IntegerField', 25 | FIELD_TYPE.TINY_BLOB: 'TextField', 26 | FIELD_TYPE.MEDIUM_BLOB: 'TextField', 27 | FIELD_TYPE.LONG_BLOB: 'TextField', 28 | FIELD_TYPE.VAR_STRING: 'CharField', 29 | } 30 | 31 | def get_table_list(self, cursor): 32 | "Returns a list of table names in the current database." 33 | cursor.execute("SHOW TABLES") 34 | return [row[0] for row in cursor.fetchall()] 35 | 36 | def get_table_description(self, cursor, table_name): 37 | "Returns a description of the table, with the DB-API cursor.description interface." 38 | cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name)) 39 | return cursor.description 40 | 41 | def _name_to_index(self, cursor, table_name): 42 | """ 43 | Returns a dictionary of {field_name: field_index} for the given table. 44 | Indexes are 0-based. 45 | """ 46 | return dict([(d[0], i) for i, d in enumerate(self.get_table_description(cursor, table_name))]) 47 | 48 | def get_relations(self, cursor, table_name): 49 | """ 50 | Returns a dictionary of {field_index: (field_index_other_table, other_table)} 51 | representing all relationships to the given table. Indexes are 0-based. 52 | """ 53 | my_field_dict = self._name_to_index(cursor, table_name) 54 | constraints = [] 55 | relations = {} 56 | try: 57 | # This should work for MySQL 5.0. 58 | cursor.execute(""" 59 | SELECT column_name, referenced_table_name, referenced_column_name 60 | FROM information_schema.key_column_usage 61 | WHERE table_name = %s 62 | AND table_schema = DATABASE() 63 | AND referenced_table_name IS NOT NULL 64 | AND referenced_column_name IS NOT NULL""", [table_name]) 65 | constraints.extend(cursor.fetchall()) 66 | except (KeyError): # Coloquei qualquer excessao eu quero ver quebrar no appengine 67 | # Fall back to "SHOW CREATE TABLE", for previous MySQL versions. 68 | # Go through all constraints and save the equal matches. 69 | cursor.execute("SHOW CREATE TABLE %s" % self.connection.ops.quote_name(table_name)) 70 | for row in cursor.fetchall(): 71 | pos = 0 72 | while True: 73 | match = foreign_key_re.search(row[1], pos) 74 | if match == None: 75 | break 76 | pos = match.end() 77 | constraints.append(match.groups()) 78 | 79 | for my_fieldname, other_table, other_field in constraints: 80 | other_field_index = self._name_to_index(cursor, other_table)[other_field] 81 | my_field_index = my_field_dict[my_fieldname] 82 | relations[my_field_index] = (other_field_index, other_table) 83 | 84 | return relations 85 | 86 | def get_indexes(self, cursor, table_name): 87 | """ 88 | Returns a dictionary of fieldname -> infodict for the given table, 89 | where each infodict is in the format: 90 | {'primary_key': boolean representing whether it's the primary key, 91 | 'unique': boolean representing whether it's a unique index} 92 | """ 93 | cursor.execute("SHOW INDEX FROM %s" % self.connection.ops.quote_name(table_name)) 94 | indexes = {} 95 | for row in cursor.fetchall(): 96 | indexes[row[4]] = {'primary_key': (row[2] == 'PRIMARY'), 'unique': not bool(row[1])} 97 | return indexes 98 | 99 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/storage.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | try: 4 | from cStringIO import StringIO 5 | except ImportError: 6 | from StringIO import StringIO 7 | 8 | from django.conf import settings 9 | from django.core.files.base import File 10 | from django.core.files.storage import Storage 11 | from django.core.files.uploadedfile import UploadedFile 12 | from django.core.files.uploadhandler import FileUploadHandler, \ 13 | StopFutureHandlers 14 | from django.core.exceptions import ImproperlyConfigured 15 | from django.http import HttpResponse 16 | from django.utils.encoding import smart_str, force_unicode 17 | 18 | from google.appengine.ext.blobstore import BlobInfo, BlobKey, delete, \ 19 | create_upload_url, BLOB_KEY_HEADER, BLOB_RANGE_HEADER, BlobReader 20 | 21 | def prepare_upload(request, url, **kwargs): 22 | return create_upload_url(url), {} 23 | 24 | def serve_file(request, file, save_as, content_type, **kwargs): 25 | if hasattr(file, 'file') and hasattr(file.file, 'blobstore_info'): 26 | blobkey = file.file.blobstore_info.key() 27 | elif hasattr(file, 'blobstore_info'): 28 | blobkey = file.blobstore_info.key() 29 | else: 30 | raise ValueError("The provided file can't be served via the " 31 | "Google App Engine Blobstore.") 32 | response = HttpResponse(content_type=content_type) 33 | response[BLOB_KEY_HEADER] = str(blobkey) 34 | response['Accept-Ranges'] = 'bytes' 35 | http_range = request.META.get('HTTP_RANGE') 36 | if http_range is not None: 37 | response[BLOB_RANGE_HEADER] = http_range 38 | if save_as: 39 | response['Content-Disposition'] = smart_str(u'attachment; filename=%s' % save_as) 40 | if file.size is not None: 41 | response['Content-Length'] = file.size 42 | return response 43 | 44 | class BlobstoreStorage(Storage): 45 | """Google App Engine Blobstore storage backend""" 46 | 47 | def _open(self, name, mode='rb'): 48 | return BlobstoreFile(name, mode, self) 49 | 50 | def _save(self, name, content): 51 | name = name.replace('\\', '/') 52 | if hasattr(content, 'file') and hasattr(content.file, 'blobstore_info'): 53 | data = content.file.blobstore_info 54 | elif hasattr(content, 'blobstore_info'): 55 | data = content.blobstore_info 56 | else: 57 | raise ValueError("The App Engine storage backend only supports " 58 | "BlobstoreFile instances or File instances " 59 | "whose file attribute is a BlobstoreFile.") 60 | 61 | if isinstance(data, (BlobInfo, BlobKey)): 62 | # We change the file name to the BlobKey's str() value 63 | if isinstance(data, BlobInfo): 64 | data = data.key() 65 | return '%s/%s' % (data, name.lstrip('/')) 66 | else: 67 | raise ValueError("The App Engine Blobstore only supports " 68 | "BlobInfo values. Data can't be uploaded " 69 | "directly. You have to use the file upload " 70 | "handler.") 71 | 72 | def delete(self, name): 73 | delete(self._get_key(name)) 74 | 75 | def exists(self, name): 76 | return self._get_blobinfo(name) is not None 77 | 78 | def size(self, name): 79 | return self._get_blobinfo(name).size 80 | 81 | def url(self, name): 82 | raise NotImplementedError() 83 | 84 | def get_valid_name(self, name): 85 | return force_unicode(name).strip().replace('\\', '/') 86 | 87 | def get_available_name(self, name): 88 | return name.replace('\\', '/') 89 | 90 | def _get_key(self, name): 91 | return BlobKey(name.split('/', 1)[0]) 92 | 93 | def _get_blobinfo(self, name): 94 | return BlobInfo.get(self._get_key(name)) 95 | 96 | class BlobstoreFile(File): 97 | def __init__(self, name, mode, storage): 98 | self.name = name 99 | self._storage = storage 100 | self._mode = mode 101 | self.blobstore_info = storage._get_blobinfo(name) 102 | 103 | @property 104 | def size(self): 105 | return self.blobstore_info.size 106 | 107 | def write(self, content): 108 | raise NotImplementedError() 109 | 110 | @property 111 | def file(self): 112 | if not hasattr(self, '_file'): 113 | self._file = BlobReader(self.blobstore_info.key()) 114 | return self._file 115 | 116 | class BlobstoreFileUploadHandler(FileUploadHandler): 117 | """ 118 | File upload handler for the Google App Engine Blobstore 119 | """ 120 | 121 | def new_file(self, *args, **kwargs): 122 | super(BlobstoreFileUploadHandler, self).new_file(*args, **kwargs) 123 | blobkey = self.content_type_extra.get('blob-key') 124 | self.active = blobkey is not None 125 | if self.active: 126 | self.blobkey = BlobKey(blobkey) 127 | raise StopFutureHandlers() 128 | 129 | def receive_data_chunk(self, raw_data, start): 130 | """ 131 | Add the data to the StringIO file. 132 | """ 133 | if not self.active: 134 | return raw_data 135 | 136 | def file_complete(self, file_size): 137 | """ 138 | Return a file object if we're activated. 139 | """ 140 | if not self.active: 141 | return 142 | 143 | return BlobstoreUploadedFile( 144 | blobinfo=BlobInfo(self.blobkey), 145 | charset=self.charset) 146 | 147 | class BlobstoreUploadedFile(UploadedFile): 148 | """ 149 | A file uploaded into memory (i.e. stream-to-memory). 150 | """ 151 | def __init__(self, blobinfo, charset): 152 | super(BlobstoreUploadedFile, self).__init__( 153 | BlobReader(blobinfo.key()), blobinfo.filename, 154 | blobinfo.content_type, blobinfo.size, charset) 155 | self.blobstore_info = blobinfo 156 | 157 | def open(self, mode=None): 158 | pass 159 | 160 | def chunks(self, chunk_size=1024*128): 161 | self.file.seek(0) 162 | while True: 163 | content = self.read(chunk_size) 164 | if not content: 165 | break 166 | yield content 167 | 168 | def multiple_chunks(self, chunk_size=1024*128): 169 | return True 170 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/db/backend/stubs.py: -------------------------------------------------------------------------------- 1 | from ...utils import appid, have_appserver, on_production_server 2 | from google.appengine.ext.testbed import Testbed 3 | from urllib2 import HTTPError, URLError 4 | import logging 5 | import time 6 | 7 | REMOTE_API_SCRIPTS = ( 8 | '$PYTHON_LIB/google/appengine/ext/remote_api/handler.py', 9 | 'google.appengine.ext.remote_api.handler.application', 10 | ) 11 | 12 | def auth_func(): 13 | import getpass 14 | return raw_input('Login via Google Account (see note above if login fails): '), getpass.getpass('Password: ') 15 | 16 | def rpc_server_factory(*args, ** kwargs): 17 | from google.appengine.tools import appengine_rpc 18 | kwargs['save_cookies'] = True 19 | return appengine_rpc.HttpRpcServer(*args, ** kwargs) 20 | 21 | class StubManager(object): 22 | def __init__(self): 23 | self.testbed = Testbed() 24 | self.active_stubs = None 25 | self.pre_test_stubs = None 26 | 27 | def setup_stubs(self, connection): 28 | if self.active_stubs is not None: 29 | return 30 | if not have_appserver: 31 | self.setup_local_stubs(connection) 32 | 33 | def activate_test_stubs(self): 34 | if self.active_stubs == 'test': 35 | return 36 | self.testbed.activate() 37 | self.pre_test_stubs = self.active_stubs 38 | self.active_stubs = 'test' 39 | self.testbed.init_datastore_v3_stub() 40 | self.testbed.init_memcache_stub() 41 | self.testbed.init_taskqueue_stub() 42 | self.testbed.init_urlfetch_stub() 43 | self.testbed.init_user_stub() 44 | self.testbed.init_xmpp_stub() 45 | self.testbed.init_channel_stub() 46 | self.setup_local_rdbms(connection) 47 | 48 | def deactivate_test_stubs(self): 49 | if self.active_stubs == 'test': 50 | self.testbed.deactivate() 51 | self.active_stubs = self.pre_test_stubs 52 | 53 | def setup_local_stubs(self, connection): 54 | if self.active_stubs == 'local': 55 | return 56 | 57 | from google.appengine.tools import dev_appserver_main 58 | args = dev_appserver_main.DEFAULT_ARGS.copy() 59 | args.update(connection.settings_dict.get('DEV_APPSERVER_OPTIONS', {})) 60 | log_level = logging.WARNING 61 | logging.getLogger().setLevel(log_level) 62 | from google.appengine.tools import dev_appserver 63 | dev_appserver.SetupStubs('dev~' + appid, **args) 64 | self.setup_local_rdbms(connection) 65 | 66 | self.active_stubs = 'local' 67 | 68 | def setup_remote_stubs(self, connection): 69 | if self.active_stubs == 'remote': 70 | return 71 | 72 | self.setup_default_rdbms(connection) 73 | if not connection.remote_api_path: 74 | from ...utils import appconfig 75 | for handler in appconfig.handlers: 76 | if handler.script in REMOTE_API_SCRIPTS: 77 | connection.remote_api_path = handler.url.split('(', 1)[0] 78 | break 79 | server = '%s.%s' % (connection.remote_app_id, connection.domain) 80 | remote_url = 'https://%s%s' % (server, connection.remote_api_path) 81 | logging.info('Setting up remote_api for "%s" at %s' % 82 | (connection.remote_app_id, remote_url)) 83 | if not have_appserver: 84 | print('Connecting to remote_api handler.\n\n' 85 | 'IMPORTANT: Check your login method settings in the ' 86 | 'App Engine Dashboard if you have problems logging in. ' 87 | 'Login is only supported for Google Accounts.\n') 88 | from google.appengine.ext.remote_api import remote_api_stub 89 | remote_api_stub.ConfigureRemoteApi(None, 90 | connection.remote_api_path, auth_func, servername=server, 91 | secure=connection.secure_remote_api, 92 | rpc_server_factory=rpc_server_factory) 93 | retry_delay = 1 94 | while retry_delay <= 16: 95 | try: 96 | remote_api_stub.MaybeInvokeAuthentication() 97 | except HTTPError, e: 98 | if not have_appserver: 99 | print 'Retrying in %d seconds...' % retry_delay 100 | time.sleep(retry_delay) 101 | retry_delay *= 2 102 | else: 103 | break 104 | else: 105 | try: 106 | remote_api_stub.MaybeInvokeAuthentication() 107 | except HTTPError, e: 108 | raise URLError("%s\n" 109 | "Couldn't reach remote_api handler at %s.\n" 110 | "Make sure you've deployed your project and " 111 | "installed a remote_api handler in app.yaml. " 112 | "Note that login is only supported for " 113 | "Google Accounts. Make sure you've configured " 114 | "the correct authentication method in the " 115 | "App Engine Dashboard." 116 | % (e, remote_url)) 117 | logging.info('Now using the remote datastore for "%s" at %s' % 118 | (connection.remote_app_id, remote_url)) 119 | self.active_stubs = 'remote' 120 | 121 | 122 | def setup_local_rdbms(self, connection): 123 | 124 | from ...db.backend.base import DatabaseWrapper 125 | 126 | if isinstance(connection, DatabaseWrapper): 127 | from google.appengine.api import rdbms_mysqldb 128 | from google.appengine import api 129 | import sys 130 | 131 | # Store the defalt rdbms if i need to restore it 132 | from google.appengine.api import rdbms 133 | self._default_rdbms = rdbms 134 | sys.modules['google.appengine.api.rdbms'] = rdbms_mysqldb 135 | api.rdbms = rdbms_mysqldb 136 | rdbms_mysqldb.SetConnectKwargs( 137 | host=connection.settings_dict["HOST"], 138 | user=connection.settings_dict["USER"], 139 | passwd=connection.settings_dict["PASSWORD"] 140 | ) 141 | rdbms_mysqldb.connect(database='') 142 | 143 | def setup_default_rdbms(self,connection): 144 | if hasattr(self,"_default_rdbms"): 145 | import sys 146 | from google.appengine import api 147 | from google.appengine.api import rdbms 148 | sys.modules['google.appengine.api.rdbms'] = self._default_rdbms 149 | api.rdbms = self._default_rdbms 150 | 151 | 152 | stub_manager = StubManager() 153 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/management/commands/runserver.py: -------------------------------------------------------------------------------- 1 | from optparse import make_option 2 | import logging 3 | import sys 4 | 5 | from django.db import connections 6 | from ...boot import PROJECT_DIR 7 | from ...db.backend.base import DatabaseWrapper 8 | from django.core.management.base import BaseCommand 9 | from django.core.management.commands.runserver import BaseRunserverCommand 10 | from django.core.exceptions import ImproperlyConfigured 11 | 12 | from google.appengine.tools import dev_appserver_main 13 | from django.core.management import call_command 14 | 15 | class Command(BaseRunserverCommand): 16 | """Overrides the default Django runserver command. 17 | 18 | Instead of starting the default Django development server this command 19 | fires up a copy of the full fledged App Engine dev_appserver that emulates 20 | the live environment your application will be deployed to. 21 | """ 22 | 23 | option_list = BaseCommand.option_list + ( 24 | make_option('--debug', action='store_true', default=False, 25 | help='Prints verbose debugging messages to the console while running.'), 26 | make_option('--debug_imports', action='store_true', default=False, 27 | help='Prints debugging messages related to importing modules, including \ 28 | search paths and errors.'), 29 | make_option('-c', '--clear_datastore', action='store_true', default=False, 30 | help='Clears the datastore data and history files before starting the web server.'), 31 | make_option('--high_replication', action='store_true', default=False, 32 | help='Use the high replication datastore consistency model.'), 33 | make_option('--require_indexes', action='store_true', default=False, 34 | help="""Disables automatic generation of entries in the index.yaml file. Instead, when 35 | the application makes a query that requires that its index be defined in the 36 | file and the index definition is not found, an exception will be raised, 37 | similar to what would happen when running on App Engine."""), 38 | make_option('--enable_sendmail', action='store_true', default=False, 39 | help='Uses the local computer\'s Sendmail installation for sending email messages.'), 40 | make_option('--datastore_path', 41 | help="""The path to use for the local datastore data file. The server creates this file 42 | if it does not exist."""), 43 | make_option('--history_path', 44 | help="""The path to use for the local datastore history file. The server uses the query 45 | history file to generate entries for index.yaml."""), 46 | make_option('--login_url', 47 | help='The relative URL to use for the Users sign-in page. Default is /_ah/login.'), 48 | make_option('--smtp_host', 49 | help='The hostname of the SMTP server to use for sending email messages.'), 50 | make_option('--smtp_port', 51 | help='The port number of the SMTP server to use for sending email messages.'), 52 | make_option('--smtp_user', 53 | help='The username to use with the SMTP server for sending email messages.'), 54 | make_option('--smtp_password', 55 | help='The password to use with the SMTP server for sending email messages.'), 56 | make_option('--use_sqlite', action='store_true', default=False, 57 | help='Use the new, SQLite datastore stub.'), 58 | ) 59 | 60 | help = 'Runs a copy of the App Engine development server.' 61 | args = '[optional port number, or ipaddr:port]' 62 | 63 | def create_parser(self, prog_name, subcommand): 64 | """ 65 | Create and return the ``OptionParser`` which will be used to 66 | parse the arguments to this command. 67 | 68 | """ 69 | # hack __main__ so --help in dev_appserver_main works OK. 70 | sys.modules['__main__'] = dev_appserver_main 71 | return super(Command, self).create_parser(prog_name, subcommand) 72 | 73 | def run_from_argv(self, argv): 74 | """ 75 | Captures the program name, usually "manage.py" 76 | """ 77 | 78 | self.progname = argv[0] 79 | super(Command, self).run_from_argv(argv) 80 | 81 | def run(self, *args, **options): 82 | """ 83 | Starts the App Engine dev_appserver program for the Django project. 84 | The appserver is run with default parameters. If you need to pass any special 85 | parameters to the dev_appserver you will have to invoke it manually. 86 | 87 | Unlike the normal devserver, does not use the autoreloader as 88 | App Engine dev_appserver needs to be run from the main thread 89 | """ 90 | 91 | args = [] 92 | # Set bind ip/port if specified. 93 | if self.addr: 94 | args.extend(["--address", self.addr]) 95 | if self.port: 96 | args.extend(["--port", self.port]) 97 | 98 | # If runserver is called using handle(), progname will not be set 99 | if not hasattr(self, 'progname'): 100 | self.progname = "manage.py" 101 | 102 | # Add email settings 103 | from django.conf import settings 104 | if not options.get('smtp_host', None) and not options.get('enable_sendmail', None): 105 | args.extend(['--smtp_host', settings.EMAIL_HOST, 106 | '--smtp_port', str(settings.EMAIL_PORT), 107 | '--smtp_user', settings.EMAIL_HOST_USER, 108 | '--smtp_password', settings.EMAIL_HOST_PASSWORD]) 109 | 110 | # Pass the application specific datastore location to the server. 111 | preset_options = {} 112 | for name in connections: 113 | connection = connections[name] 114 | if isinstance(connection, DatabaseWrapper): 115 | args.extend(["--mysql_user", connection.settings_dict.get("USER")]) 116 | args.extend(["--mysql_password", connection.settings_dict.get("PASSWORD")]) 117 | #args.extend(["--mysql_port", "root") 118 | #args.extend(["--mysql_host", "root") 119 | 120 | preset_options = connection.settings_dict.get('DEV_APPSERVER_OPTIONS', {}) 121 | break 122 | 123 | # Process the rest of the options here 124 | bool_options = ['debug', 'debug_imports', 'clear_datastore', 'require_indexes', 125 | 'high_replication', 'enable_sendmail', 'use_sqlite',] 126 | for opt in bool_options: 127 | if options[opt] != False: 128 | args.append("--%s" % opt) 129 | 130 | str_options = ['datastore_path', 'history_path', 'login_url', 'smtp_host', 'smtp_port', 131 | 'smtp_user', 'smtp_password',] 132 | for opt in str_options: 133 | if options.get(opt, None) != None: 134 | args.extend(["--%s" % opt, options[opt]]) 135 | 136 | # Fill any non-overridden options with presets from settings 137 | for opt, value in preset_options.items(): 138 | arg = "--%s" % opt 139 | if arg not in args: 140 | if value and opt in bool_options: 141 | args.append(arg) 142 | elif opt in str_options: 143 | args.extend([arg, value]) 144 | # TODO: issue warning about bogus option key(s)? 145 | 146 | # Reset logging level to INFO as dev_appserver will spew tons of debug logs 147 | logging.getLogger().setLevel(logging.INFO) 148 | logging.info(args) 149 | logging.info(PROJECT_DIR) 150 | # Append the current working directory to the arguments. 151 | 152 | 153 | dev_appserver_main.main([self.progname] + args + [PROJECT_DIR]) 154 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/boot.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | import sys 4 | 5 | PROJECT_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) 6 | DATA_ROOT = os.path.join(PROJECT_DIR, '.gaedata') 7 | 8 | # Overrides for os.environ 9 | env_ext = {'DJANGO_SETTINGS_MODULE': 'settings'} 10 | 11 | def setup_env(): 12 | """Configures app engine environment for command-line apps.""" 13 | # Try to import the appengine code from the system path. 14 | try: 15 | from google.appengine.api import apiproxy_stub_map 16 | except ImportError: 17 | for k in [k for k in sys.modules if k.startswith('google')]: 18 | del sys.modules[k] 19 | 20 | # Not on the system path. Build a list of alternative paths where it 21 | # may be. First look within the project for a local copy, then look for 22 | # where the Mac OS SDK installs it. 23 | paths = [os.path.join(PROJECT_DIR, '.google_appengine'), 24 | os.environ.get('APP_ENGINE_SDK'), 25 | '/usr/local/google_appengine', 26 | '/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine'] 27 | for path in os.environ.get('PATH', '').split(os.pathsep): 28 | path = path.rstrip(os.sep) 29 | if path.endswith('google_appengine'): 30 | paths.append(path) 31 | if os.name in ('nt', 'dos'): 32 | path = r'%(PROGRAMFILES)s\Google\google_appengine' % os.environ 33 | paths.append(path) 34 | # Loop through all possible paths and look for the SDK dir. 35 | sdk_path = None 36 | for path in paths: 37 | if not path: 38 | continue 39 | path = os.path.expanduser(path) 40 | path = os.path.realpath(path) 41 | if os.path.exists(path): 42 | sdk_path = path 43 | break 44 | if sdk_path is None: 45 | # The SDK could not be found in any known location. 46 | sys.stderr.write('The Google App Engine SDK could not be found!\n' 47 | "Make sure it's accessible via your PATH " 48 | "environment and called google_appengine.\n") 49 | sys.exit(1) 50 | # Add the SDK and the libraries within it to the system path. 51 | extra_paths = [sdk_path] 52 | lib = os.path.join(sdk_path, 'lib') 53 | # Automatically add all packages in the SDK's lib folder: 54 | for name in os.listdir(lib): 55 | root = os.path.join(lib, name) 56 | subdir = name 57 | # Package can be under 'lib///' or 'lib//lib//' 58 | detect = (os.path.join(root, subdir), os.path.join(root, 'lib', subdir)) 59 | for path in detect: 60 | if os.path.isdir(path): 61 | extra_paths.append(os.path.dirname(path)) 62 | break 63 | else: 64 | if name == 'webapp2': 65 | extra_paths.append(root) 66 | sys.path = extra_paths + sys.path 67 | from google.appengine.api import apiproxy_stub_map 68 | 69 | 70 | 71 | setup_project() 72 | from .utils import have_appserver 73 | if have_appserver: 74 | # App Engine's threading.local is broken 75 | setup_threading() 76 | elif not os.path.exists(DATA_ROOT): 77 | os.mkdir(DATA_ROOT) 78 | setup_logging() 79 | 80 | if not have_appserver: 81 | # Patch Django to support loading management commands from zip files 82 | from django.core import management 83 | management.find_commands = find_commands 84 | 85 | def find_commands(management_dir): 86 | """ 87 | Given a path to a management directory, returns a list of all the command 88 | names that are available. 89 | This version works for django deployments which are file based or 90 | contained in a ZIP (in sys.path). 91 | 92 | Returns an empty list if no commands are defined. 93 | """ 94 | import pkgutil 95 | return [modname for importer, modname, ispkg in pkgutil.iter_modules( 96 | [os.path.join(management_dir, 'commands')]) if not ispkg] 97 | 98 | def setup_threading(): 99 | if sys.version_info >= (2, 7): 100 | return 101 | # XXX: On Python 2.5 GAE's threading.local doesn't work correctly with subclassing 102 | try: 103 | from django.utils._threading_local import local 104 | import threading 105 | threading.local = local 106 | except ImportError: 107 | pass 108 | 109 | def setup_logging(): 110 | # Fix Python 2.6 logging module 111 | logging.logMultiprocessing = 0 112 | 113 | # Enable logging 114 | level = logging.DEBUG 115 | from .utils import have_appserver 116 | if have_appserver: 117 | # We can't import settings at this point when running a normal 118 | # manage.py command because this module gets imported from settings.py 119 | from django.conf import settings 120 | if not settings.DEBUG: 121 | level = logging.INFO 122 | logging.getLogger().setLevel(level) 123 | 124 | def setup_project(): 125 | from .utils import have_appserver, on_production_server 126 | if have_appserver: 127 | # This fixes a pwd import bug for os.path.expanduser() 128 | env_ext['HOME'] = PROJECT_DIR 129 | 130 | # The dev_appserver creates a sandbox which restricts access to certain 131 | # modules and builtins in order to emulate the production environment. 132 | # Here we get the subprocess module back into the dev_appserver sandbox. 133 | # This module is just too important for development. 134 | # Also we add the compiler/parser module back and enable https connections 135 | # (seem to be broken on Windows because the _ssl module is disallowed). 136 | if not have_appserver: 137 | from google.appengine.tools import dev_appserver 138 | try: 139 | # Backup os.environ. It gets overwritten by the dev_appserver, 140 | # but it's needed by the subprocess module. 141 | env = dev_appserver.DEFAULT_ENV 142 | dev_appserver.DEFAULT_ENV = os.environ.copy() 143 | dev_appserver.DEFAULT_ENV.update(env) 144 | # Backup the buffer() builtin. The subprocess in Python 2.5 on 145 | # Linux and OS X uses needs it, but the dev_appserver removes it. 146 | dev_appserver.buffer = buffer 147 | 148 | 149 | except AttributeError: 150 | logging.warn('Could not patch the default environment. ' 151 | 'The subprocess module will not work correctly.') 152 | 153 | try: 154 | # Allow importing compiler/parser, _ssl (for https), 155 | # _io for Python 2.7 io support on OS X 156 | dev_appserver.HardenedModulesHook._WHITE_LIST_C_MODULES.extend( 157 | ('parser', '_ssl', '_io')) 158 | except AttributeError: 159 | logging.warn('Could not patch modules whitelist. ' 160 | 'The compiler and parser modules will not work and ' 161 | 'SSL support is disabled.') 162 | elif not on_production_server: 163 | try: 164 | # Restore the real subprocess module 165 | from google.appengine.api.mail_stub import subprocess 166 | sys.modules['subprocess'] = subprocess 167 | # Re-inject the buffer() builtin into the subprocess module 168 | from google.appengine.tools import dev_appserver 169 | subprocess.buffer = dev_appserver.buffer 170 | except Exception, e: 171 | logging.warn('Could not add the subprocess module to the sandbox: %s' % e) 172 | 173 | os.environ.update(env_ext) 174 | 175 | extra_paths = [PROJECT_DIR, os.path.join(os.path.dirname(__file__), 'lib')] 176 | zip_packages_dir = os.path.join(PROJECT_DIR, 'zip-packages') 177 | 178 | # We support zipped packages in the common and project folders. 179 | if os.path.isdir(zip_packages_dir): 180 | for zip_package in os.listdir(zip_packages_dir): 181 | extra_paths.append(os.path.join(zip_packages_dir, zip_package)) 182 | 183 | # App Engine causes main.py to be reloaded if an exception gets raised 184 | # on the first request of a main.py instance, so don't call setup_project() 185 | # multiple times. We ensure this indirectly by checking if we've already 186 | # modified sys.path, already. 187 | if len(sys.path) < len(extra_paths) or \ 188 | sys.path[:len(extra_paths)] != extra_paths: 189 | for path in extra_paths: 190 | while path in sys.path: 191 | sys.path.remove(path) 192 | sys.path = extra_paths + sys.path 193 | 194 | 195 | 196 | 197 | -------------------------------------------------------------------------------- /djangoappengine_rdbms/db/backend/base.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | 4 | 5 | from ...utils import appid, on_production_server 6 | from .stubs import stub_manager 7 | 8 | from django.db.backends import * 9 | from django.db.backends.signals import connection_created 10 | from django.db.backends.mysql.client import DatabaseClient 11 | from django.db.backends.mysql.creation import DatabaseCreation 12 | from introspection import DatabaseIntrospection 13 | from django.db.backends.mysql.validation import DatabaseValidation 14 | from django.utils.safestring import SafeString, SafeUnicode 15 | 16 | # Raise exceptions for database warnings if DEBUG is on 17 | from django.conf import settings 18 | 19 | 20 | class DatabaseFeatures(BaseDatabaseFeatures): 21 | empty_fetchmany_value = () 22 | update_can_self_select = False 23 | allows_group_by_pk = True 24 | related_fields_match_type = True 25 | allow_sliced_subqueries = False 26 | supports_forward_references = False 27 | supports_long_model_names = False 28 | supports_microsecond_precision = False 29 | supports_regex_backreferencing = False 30 | supports_date_lookup_using_string = False 31 | supports_timezones = False 32 | requires_explicit_null_ordering_when_grouping = True 33 | allows_primary_key_0 = False 34 | 35 | def _can_introspect_foreign_keys(self): 36 | "Confirm support for introspected foreign keys" 37 | cursor = self.connection.cursor() 38 | cursor.execute('CREATE TABLE INTROSPECT_TEST (X INT)') 39 | # This command is MySQL specific; the second column 40 | # will tell you the default table type of the created 41 | # table. Since all Django's test tables will have the same 42 | # table type, that's enough to evaluate the feature. 43 | cursor.execute('SHOW TABLE STATUS WHERE Name="INTROSPECT_TEST"') 44 | result = cursor.fetchone() 45 | cursor.execute('DROP TABLE INTROSPECT_TEST') 46 | return result[1] != 'MyISAM' 47 | 48 | class DatabaseOperations(BaseDatabaseOperations): 49 | compiler_module = "django.db.backends.mysql.compiler" 50 | 51 | def date_extract_sql(self, lookup_type, field_name): 52 | # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html 53 | if lookup_type == 'week_day': 54 | # DAYOFWEEK() returns an integer, 1-7, Sunday=1. 55 | # Note: WEEKDAY() returns 0-6, Monday=0. 56 | return "DAYOFWEEK(%s)" % field_name 57 | else: 58 | return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name) 59 | 60 | def date_trunc_sql(self, lookup_type, field_name): 61 | fields = ['year', 'month', 'day', 'hour', 'minute', 'second'] 62 | format = ('%%Y-', '%%m', '-%%d', ' %%H:', '%%i', ':%%s') # Use double percents to escape. 63 | format_def = ('0000-', '01', '-01', ' 00:', '00', ':00') 64 | try: 65 | i = fields.index(lookup_type) + 1 66 | except ValueError: 67 | sql = field_name 68 | else: 69 | format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]]) 70 | sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str) 71 | return sql 72 | 73 | def date_interval_sql(self, sql, connector, timedelta): 74 | return "(%s %s INTERVAL '%d 0:0:%d:%d' DAY_MICROSECOND)" % (sql, connector, 75 | timedelta.days, timedelta.seconds, timedelta.microseconds) 76 | 77 | def drop_foreignkey_sql(self): 78 | return "DROP FOREIGN KEY" 79 | 80 | def force_no_ordering(self): 81 | """ 82 | "ORDER BY NULL" prevents MySQL from implicitly ordering by grouped 83 | columns. If no ordering would otherwise be applied, we don't want any 84 | implicit sorting going on. 85 | """ 86 | return ["NULL"] 87 | 88 | def fulltext_search_sql(self, field_name): 89 | return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name 90 | 91 | def no_limit_value(self): 92 | # 2**64 - 1, as recommended by the MySQL documentation 93 | return 18446744073709551615L 94 | 95 | def quote_name(self, name): 96 | if name.startswith("`") and name.endswith("`"): 97 | return name # Quoting once is enough. 98 | return "`%s`" % name 99 | 100 | def random_function_sql(self): 101 | return 'RAND()' 102 | 103 | def sql_flush(self, style, tables, sequences): 104 | # NB: The generated SQL below is specific to MySQL 105 | # 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements 106 | # to clear all tables of all data 107 | if tables: 108 | sql = ['SET FOREIGN_KEY_CHECKS = 0;'] 109 | for table in tables: 110 | sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self.quote_name(table)))) 111 | sql.append('SET FOREIGN_KEY_CHECKS = 1;') 112 | 113 | # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements 114 | # to reset sequence indices 115 | sql.extend(["%s %s %s %s %s;" % \ 116 | (style.SQL_KEYWORD('ALTER'), 117 | style.SQL_KEYWORD('TABLE'), 118 | style.SQL_TABLE(self.quote_name(sequence['table'])), 119 | style.SQL_KEYWORD('AUTO_INCREMENT'), 120 | style.SQL_FIELD('= 1'), 121 | ) for sequence in sequences]) 122 | return sql 123 | else: 124 | return [] 125 | 126 | def value_to_db_datetime(self, value): 127 | if value is None: 128 | return None 129 | 130 | # MySQL doesn't support tz-aware datetimes 131 | if value.tzinfo is not None: 132 | raise ValueError("MySQL backend does not support timezone-aware datetimes.") 133 | 134 | # MySQL doesn't support microseconds 135 | return unicode(value.replace(microsecond=0)) 136 | 137 | def value_to_db_time(self, value): 138 | if value is None: 139 | return None 140 | 141 | # MySQL doesn't support tz-aware datetimes 142 | if value.tzinfo is not None: 143 | raise ValueError("MySQL backend does not support timezone-aware datetimes.") 144 | 145 | # MySQL doesn't support microseconds 146 | return unicode(value.replace(microsecond=0)) 147 | 148 | def year_lookup_bounds(self, value): 149 | # Again, no microseconds 150 | first = '%s-01-01 00:00:00' 151 | second = '%s-12-31 23:59:59.99' 152 | return [first % value, second % value] 153 | 154 | def max_name_length(self): 155 | return 64 156 | 157 | 158 | 159 | 160 | 161 | class DatabaseWrapper(BaseDatabaseWrapper): 162 | vendor = 'mysql' 163 | operators = { 164 | 'exact': '= %s', 165 | 'iexact': 'LIKE %s', 166 | 'contains': 'LIKE BINARY %s', 167 | 'icontains': 'LIKE %s', 168 | 'regex': 'REGEXP BINARY %s', 169 | 'iregex': 'REGEXP %s', 170 | 'gt': '> %s', 171 | 'gte': '>= %s', 172 | 'lt': '< %s', 173 | 'lte': '<= %s', 174 | 'startswith': 'LIKE BINARY %s', 175 | 'endswith': 'LIKE BINARY %s', 176 | 'istartswith': 'LIKE %s', 177 | 'iendswith': 'LIKE %s', 178 | } 179 | 180 | def __init__(self, *args, **kwargs): 181 | super(DatabaseWrapper, self).__init__(*args, **kwargs) 182 | 183 | self.server_version = None 184 | self.features = DatabaseFeatures(self) 185 | self.ops = DatabaseOperations() 186 | self.client = DatabaseClient(self) 187 | self.creation = DatabaseCreation(self) 188 | self.introspection = DatabaseIntrospection(self) 189 | self.validation = DatabaseValidation(self) 190 | 191 | self.remote_app_id = self.settings_dict.get('REMOTE_APP_ID', appid) 192 | self.domain = self.settings_dict.get('DOMAIN', 'appspot.com') 193 | self.remote_api_path = self.settings_dict.get('REMOTE_API_PATH', None) 194 | self.secure_remote_api = self.settings_dict.get('SECURE_REMOTE_API', True) 195 | remote = self.settings_dict.get('REMOTE', False) 196 | if on_production_server: 197 | remote = False 198 | if remote: 199 | stub_manager.setup_remote_stubs(self) 200 | else: 201 | stub_manager.setup_stubs(self) 202 | 203 | 204 | def _valid_connection(self): 205 | if self.connection is not None: 206 | try: 207 | self.connection.ping() 208 | return True 209 | except DatabaseError: 210 | self.connection.close() 211 | self.connection = None 212 | return False 213 | 214 | def _cursor(self): 215 | 216 | from google.appengine.api import rdbms 217 | if not self._valid_connection(): 218 | self.connection = rdbms.connect( 219 | instance=self.settings_dict["INSTANCE"], 220 | database=self.settings_dict["NAME"]) 221 | connection_created.send(sender=self.__class__, connection=self) 222 | cursor = self.connection.cursor() 223 | 224 | return cursor 225 | 226 | def get_server_version(self): 227 | return '5.1' 228 | 229 | 230 | def _rollback(self): 231 | try: 232 | BaseDatabaseWrapper._rollback(self) 233 | except Database.NotSupportedError: 234 | pass -------------------------------------------------------------------------------- /djangoappengine_rdbms/db/backend/constants/ER.py: -------------------------------------------------------------------------------- 1 | """MySQL ER Constants 2 | 3 | These constants are error codes for the bulk of the error conditions 4 | that may occur. 5 | 6 | """ 7 | 8 | HASHCHK = 1000 9 | NISAMCHK = 1001 10 | NO = 1002 11 | YES = 1003 12 | CANT_CREATE_FILE = 1004 13 | CANT_CREATE_TABLE = 1005 14 | CANT_CREATE_DB = 1006 15 | DB_CREATE_EXISTS = 1007 16 | DB_DROP_EXISTS = 1008 17 | DB_DROP_DELETE = 1009 18 | DB_DROP_RMDIR = 1010 19 | CANT_DELETE_FILE = 1011 20 | CANT_FIND_SYSTEM_REC = 1012 21 | CANT_GET_STAT = 1013 22 | CANT_GET_WD = 1014 23 | CANT_LOCK = 1015 24 | CANT_OPEN_FILE = 1016 25 | FILE_NOT_FOUND = 1017 26 | CANT_READ_DIR = 1018 27 | CANT_SET_WD = 1019 28 | CHECKREAD = 1020 29 | DISK_FULL = 1021 30 | DUP_KEY = 1022 31 | ERROR_ON_CLOSE = 1023 32 | ERROR_ON_READ = 1024 33 | ERROR_ON_RENAME = 1025 34 | ERROR_ON_WRITE = 1026 35 | FILE_USED = 1027 36 | FILSORT_ABORT = 1028 37 | FORM_NOT_FOUND = 1029 38 | GET_ERRNO = 1030 39 | ILLEGAL_HA = 1031 40 | KEY_NOT_FOUND = 1032 41 | NOT_FORM_FILE = 1033 42 | NOT_KEYFILE = 1034 43 | OLD_KEYFILE = 1035 44 | OPEN_AS_READONLY = 1036 45 | OUTOFMEMORY = 1037 46 | OUT_OF_SORTMEMORY = 1038 47 | UNEXPECTED_EOF = 1039 48 | CON_COUNT_ERROR = 1040 49 | OUT_OF_RESOURCES = 1041 50 | BAD_HOST_ERROR = 1042 51 | HANDSHAKE_ERROR = 1043 52 | DBACCESS_DENIED_ERROR = 1044 53 | ACCESS_DENIED_ERROR = 1045 54 | NO_DB_ERROR = 1046 55 | UNKNOWN_COM_ERROR = 1047 56 | BAD_NULL_ERROR = 1048 57 | BAD_DB_ERROR = 1049 58 | TABLE_EXISTS_ERROR = 1050 59 | BAD_TABLE_ERROR = 1051 60 | NON_UNIQ_ERROR = 1052 61 | SERVER_SHUTDOWN = 1053 62 | BAD_FIELD_ERROR = 1054 63 | WRONG_FIELD_WITH_GROUP = 1055 64 | WRONG_GROUP_FIELD = 1056 65 | WRONG_SUM_SELECT = 1057 66 | WRONG_VALUE_COUNT = 1058 67 | TOO_LONG_IDENT = 1059 68 | DUP_FIELDNAME = 1060 69 | DUP_KEYNAME = 1061 70 | DUP_ENTRY = 1062 71 | WRONG_FIELD_SPEC = 1063 72 | PARSE_ERROR = 1064 73 | EMPTY_QUERY = 1065 74 | NONUNIQ_TABLE = 1066 75 | INVALID_DEFAULT = 1067 76 | MULTIPLE_PRI_KEY = 1068 77 | TOO_MANY_KEYS = 1069 78 | TOO_MANY_KEY_PARTS = 1070 79 | TOO_LONG_KEY = 1071 80 | KEY_COLUMN_DOES_NOT_EXITS = 1072 81 | BLOB_USED_AS_KEY = 1073 82 | TOO_BIG_FIELDLENGTH = 1074 83 | WRONG_AUTO_KEY = 1075 84 | READY = 1076 85 | NORMAL_SHUTDOWN = 1077 86 | GOT_SIGNAL = 1078 87 | SHUTDOWN_COMPLETE = 1079 88 | FORCING_CLOSE = 1080 89 | IPSOCK_ERROR = 1081 90 | NO_SUCH_INDEX = 1082 91 | WRONG_FIELD_TERMINATORS = 1083 92 | BLOBS_AND_NO_TERMINATED = 1084 93 | TEXTFILE_NOT_READABLE = 1085 94 | FILE_EXISTS_ERROR = 1086 95 | LOAD_INFO = 1087 96 | ALTER_INFO = 1088 97 | WRONG_SUB_KEY = 1089 98 | CANT_REMOVE_ALL_FIELDS = 1090 99 | CANT_DROP_FIELD_OR_KEY = 1091 100 | INSERT_INFO = 1092 101 | INSERT_TABLE_USED = 1093 102 | NO_SUCH_THREAD = 1094 103 | KILL_DENIED_ERROR = 1095 104 | NO_TABLES_USED = 1096 105 | TOO_BIG_SET = 1097 106 | NO_UNIQUE_LOGFILE = 1098 107 | TABLE_NOT_LOCKED_FOR_WRITE = 1099 108 | TABLE_NOT_LOCKED = 1100 109 | BLOB_CANT_HAVE_DEFAULT = 1101 110 | WRONG_DB_NAME = 1102 111 | WRONG_TABLE_NAME = 1103 112 | TOO_BIG_SELECT = 1104 113 | UNKNOWN_ERROR = 1105 114 | UNKNOWN_PROCEDURE = 1106 115 | WRONG_PARAMCOUNT_TO_PROCEDURE = 1107 116 | WRONG_PARAMETERS_TO_PROCEDURE = 1108 117 | UNKNOWN_TABLE = 1109 118 | FIELD_SPECIFIED_TWICE = 1110 119 | INVALID_GROUP_FUNC_USE = 1111 120 | UNSUPPORTED_EXTENSION = 1112 121 | TABLE_MUST_HAVE_COLUMNS = 1113 122 | RECORD_FILE_FULL = 1114 123 | UNKNOWN_CHARACTER_SET = 1115 124 | TOO_MANY_TABLES = 1116 125 | TOO_MANY_FIELDS = 1117 126 | TOO_BIG_ROWSIZE = 1118 127 | STACK_OVERRUN = 1119 128 | WRONG_OUTER_JOIN = 1120 129 | NULL_COLUMN_IN_INDEX = 1121 130 | CANT_FIND_UDF = 1122 131 | CANT_INITIALIZE_UDF = 1123 132 | UDF_NO_PATHS = 1124 133 | UDF_EXISTS = 1125 134 | CANT_OPEN_LIBRARY = 1126 135 | CANT_FIND_DL_ENTRY = 1127 136 | FUNCTION_NOT_DEFINED = 1128 137 | HOST_IS_BLOCKED = 1129 138 | HOST_NOT_PRIVILEGED = 1130 139 | PASSWORD_ANONYMOUS_USER = 1131 140 | PASSWORD_NOT_ALLOWED = 1132 141 | PASSWORD_NO_MATCH = 1133 142 | UPDATE_INFO = 1134 143 | CANT_CREATE_THREAD = 1135 144 | WRONG_VALUE_COUNT_ON_ROW = 1136 145 | CANT_REOPEN_TABLE = 1137 146 | INVALID_USE_OF_NULL = 1138 147 | REGEXP_ERROR = 1139 148 | MIX_OF_GROUP_FUNC_AND_FIELDS = 1140 149 | NONEXISTING_GRANT = 1141 150 | TABLEACCESS_DENIED_ERROR = 1142 151 | COLUMNACCESS_DENIED_ERROR = 1143 152 | ILLEGAL_GRANT_FOR_TABLE = 1144 153 | GRANT_WRONG_HOST_OR_USER = 1145 154 | NO_SUCH_TABLE = 1146 155 | NONEXISTING_TABLE_GRANT = 1147 156 | NOT_ALLOWED_COMMAND = 1148 157 | SYNTAX_ERROR = 1149 158 | DELAYED_CANT_CHANGE_LOCK = 1150 159 | TOO_MANY_DELAYED_THREADS = 1151 160 | ABORTING_CONNECTION = 1152 161 | NET_PACKET_TOO_LARGE = 1153 162 | NET_READ_ERROR_FROM_PIPE = 1154 163 | NET_FCNTL_ERROR = 1155 164 | NET_PACKETS_OUT_OF_ORDER = 1156 165 | NET_UNCOMPRESS_ERROR = 1157 166 | NET_READ_ERROR = 1158 167 | NET_READ_INTERRUPTED = 1159 168 | NET_ERROR_ON_WRITE = 1160 169 | NET_WRITE_INTERRUPTED = 1161 170 | TOO_LONG_STRING = 1162 171 | TABLE_CANT_HANDLE_BLOB = 1163 172 | TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164 173 | DELAYED_INSERT_TABLE_LOCKED = 1165 174 | WRONG_COLUMN_NAME = 1166 175 | WRONG_KEY_COLUMN = 1167 176 | WRONG_MRG_TABLE = 1168 177 | DUP_UNIQUE = 1169 178 | BLOB_KEY_WITHOUT_LENGTH = 1170 179 | PRIMARY_CANT_HAVE_NULL = 1171 180 | TOO_MANY_ROWS = 1172 181 | REQUIRES_PRIMARY_KEY = 1173 182 | NO_RAID_COMPILED = 1174 183 | UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175 184 | KEY_DOES_NOT_EXITS = 1176 185 | CHECK_NO_SUCH_TABLE = 1177 186 | CHECK_NOT_IMPLEMENTED = 1178 187 | CANT_DO_THIS_DURING_AN_TRANSACTION = 1179 188 | ERROR_DURING_COMMIT = 1180 189 | ERROR_DURING_ROLLBACK = 1181 190 | ERROR_DURING_FLUSH_LOGS = 1182 191 | ERROR_DURING_CHECKPOINT = 1183 192 | NEW_ABORTING_CONNECTION = 1184 193 | DUMP_NOT_IMPLEMENTED = 1185 194 | FLUSH_MASTER_BINLOG_CLOSED = 1186 195 | INDEX_REBUILD = 1187 196 | MASTER = 1188 197 | MASTER_NET_READ = 1189 198 | MASTER_NET_WRITE = 1190 199 | FT_MATCHING_KEY_NOT_FOUND = 1191 200 | LOCK_OR_ACTIVE_TRANSACTION = 1192 201 | UNKNOWN_SYSTEM_VARIABLE = 1193 202 | CRASHED_ON_USAGE = 1194 203 | CRASHED_ON_REPAIR = 1195 204 | WARNING_NOT_COMPLETE_ROLLBACK = 1196 205 | TRANS_CACHE_FULL = 1197 206 | SLAVE_MUST_STOP = 1198 207 | SLAVE_NOT_RUNNING = 1199 208 | BAD_SLAVE = 1200 209 | MASTER_INFO = 1201 210 | SLAVE_THREAD = 1202 211 | TOO_MANY_USER_CONNECTIONS = 1203 212 | SET_CONSTANTS_ONLY = 1204 213 | LOCK_WAIT_TIMEOUT = 1205 214 | LOCK_TABLE_FULL = 1206 215 | READ_ONLY_TRANSACTION = 1207 216 | DROP_DB_WITH_READ_LOCK = 1208 217 | CREATE_DB_WITH_READ_LOCK = 1209 218 | WRONG_ARGUMENTS = 1210 219 | NO_PERMISSION_TO_CREATE_USER = 1211 220 | UNION_TABLES_IN_DIFFERENT_DIR = 1212 221 | LOCK_DEADLOCK = 1213 222 | TABLE_CANT_HANDLE_FT = 1214 223 | CANNOT_ADD_FOREIGN = 1215 224 | NO_REFERENCED_ROW = 1216 225 | ROW_IS_REFERENCED = 1217 226 | CONNECT_TO_MASTER = 1218 227 | QUERY_ON_MASTER = 1219 228 | ERROR_WHEN_EXECUTING_COMMAND = 1220 229 | WRONG_USAGE = 1221 230 | WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222 231 | CANT_UPDATE_WITH_READLOCK = 1223 232 | MIXING_NOT_ALLOWED = 1224 233 | DUP_ARGUMENT = 1225 234 | USER_LIMIT_REACHED = 1226 235 | SPECIFIC_ACCESS_DENIED_ERROR = 1227 236 | LOCAL_VARIABLE = 1228 237 | GLOBAL_VARIABLE = 1229 238 | NO_DEFAULT = 1230 239 | WRONG_VALUE_FOR_VAR = 1231 240 | WRONG_TYPE_FOR_VAR = 1232 241 | VAR_CANT_BE_READ = 1233 242 | CANT_USE_OPTION_HERE = 1234 243 | NOT_SUPPORTED_YET = 1235 244 | MASTER_FATAL_ERROR_READING_BINLOG = 1236 245 | SLAVE_IGNORED_TABLE = 1237 246 | INCORRECT_GLOBAL_LOCAL_VAR = 1238 247 | WRONG_FK_DEF = 1239 248 | KEY_REF_DO_NOT_MATCH_TABLE_REF = 1240 249 | OPERAND_COLUMNS = 1241 250 | SUBQUERY_NO_1_ROW = 1242 251 | UNKNOWN_STMT_HANDLER = 1243 252 | CORRUPT_HELP_DB = 1244 253 | CYCLIC_REFERENCE = 1245 254 | AUTO_CONVERT = 1246 255 | ILLEGAL_REFERENCE = 1247 256 | DERIVED_MUST_HAVE_ALIAS = 1248 257 | SELECT_REDUCED = 1249 258 | TABLENAME_NOT_ALLOWED_HERE = 1250 259 | NOT_SUPPORTED_AUTH_MODE = 1251 260 | SPATIAL_CANT_HAVE_NULL = 1252 261 | COLLATION_CHARSET_MISMATCH = 1253 262 | SLAVE_WAS_RUNNING = 1254 263 | SLAVE_WAS_NOT_RUNNING = 1255 264 | TOO_BIG_FOR_UNCOMPRESS = 1256 265 | ZLIB_Z_MEM_ERROR = 1257 266 | ZLIB_Z_BUF_ERROR = 1258 267 | ZLIB_Z_DATA_ERROR = 1259 268 | CUT_VALUE_GROUP_CONCAT = 1260 269 | WARN_TOO_FEW_RECORDS = 1261 270 | WARN_TOO_MANY_RECORDS = 1262 271 | WARN_NULL_TO_NOTNULL = 1263 272 | WARN_DATA_OUT_OF_RANGE = 1264 273 | WARN_DATA_TRUNCATED = 1265 274 | WARN_USING_OTHER_HANDLER = 1266 275 | CANT_AGGREGATE_2COLLATIONS = 1267 276 | DROP_USER = 1268 277 | REVOKE_GRANTS = 1269 278 | CANT_AGGREGATE_3COLLATIONS = 1270 279 | CANT_AGGREGATE_NCOLLATIONS = 1271 280 | VARIABLE_IS_NOT_STRUCT = 1272 281 | UNKNOWN_COLLATION = 1273 282 | SLAVE_IGNORED_SSL_PARAMS = 1274 283 | SERVER_IS_IN_SECURE_AUTH_MODE = 1275 284 | WARN_FIELD_RESOLVED = 1276 285 | BAD_SLAVE_UNTIL_COND = 1277 286 | MISSING_SKIP_SLAVE = 1278 287 | UNTIL_COND_IGNORED = 1279 288 | WRONG_NAME_FOR_INDEX = 1280 289 | WRONG_NAME_FOR_CATALOG = 1281 290 | WARN_QC_RESIZE = 1282 291 | BAD_FT_COLUMN = 1283 292 | UNKNOWN_KEY_CACHE = 1284 293 | WARN_HOSTNAME_WONT_WORK = 1285 294 | UNKNOWN_STORAGE_ENGINE = 1286 295 | WARN_DEPRECATED_SYNTAX = 1287 296 | NON_UPDATABLE_TABLE = 1288 297 | FEATURE_DISABLED = 1289 298 | OPTION_PREVENTS_STATEMENT = 1290 299 | DUPLICATED_VALUE_IN_TYPE = 1291 300 | TRUNCATED_WRONG_VALUE = 1292 301 | TOO_MUCH_AUTO_TIMESTAMP_COLS = 1293 302 | INVALID_ON_UPDATE = 1294 303 | UNSUPPORTED_PS = 1295 304 | GET_ERRMSG = 1296 305 | GET_TEMPORARY_ERRMSG = 1297 306 | UNKNOWN_TIME_ZONE = 1298 307 | WARN_INVALID_TIMESTAMP = 1299 308 | INVALID_CHARACTER_STRING = 1300 309 | WARN_ALLOWED_PACKET_OVERFLOWED = 1301 310 | CONFLICTING_DECLARATIONS = 1302 311 | SP_NO_RECURSIVE_CREATE = 1303 312 | SP_ALREADY_EXISTS = 1304 313 | SP_DOES_NOT_EXIST = 1305 314 | SP_DROP_FAILED = 1306 315 | SP_STORE_FAILED = 1307 316 | SP_LILABEL_MISMATCH = 1308 317 | SP_LABEL_REDEFINE = 1309 318 | SP_LABEL_MISMATCH = 1310 319 | SP_UNINIT_VAR = 1311 320 | SP_BADSELECT = 1312 321 | SP_BADRETURN = 1313 322 | SP_BADSTATEMENT = 1314 323 | UPDATE_LOG_DEPRECATED_IGNORED = 1315 324 | UPDATE_LOG_DEPRECATED_TRANSLATED = 1316 325 | QUERY_INTERRUPTED = 1317 326 | SP_WRONG_NO_OF_ARGS = 1318 327 | SP_COND_MISMATCH = 1319 328 | SP_NORETURN = 1320 329 | SP_NORETURNEND = 1321 330 | SP_BAD_CURSOR_QUERY = 1322 331 | SP_BAD_CURSOR_SELECT = 1323 332 | SP_CURSOR_MISMATCH = 1324 333 | SP_CURSOR_ALREADY_OPEN = 1325 334 | SP_CURSOR_NOT_OPEN = 1326 335 | SP_UNDECLARED_VAR = 1327 336 | SP_WRONG_NO_OF_FETCH_ARGS = 1328 337 | SP_FETCH_NO_DATA = 1329 338 | SP_DUP_PARAM = 1330 339 | SP_DUP_VAR = 1331 340 | SP_DUP_COND = 1332 341 | SP_DUP_CURS = 1333 342 | SP_CANT_ALTER = 1334 343 | SP_SUBSELECT_NYI = 1335 344 | STMT_NOT_ALLOWED_IN_SF_OR_TRG = 1336 345 | SP_VARCOND_AFTER_CURSHNDLR = 1337 346 | SP_CURSOR_AFTER_HANDLER = 1338 347 | SP_CASE_NOT_FOUND = 1339 348 | FPARSER_TOO_BIG_FILE = 1340 349 | FPARSER_BAD_HEADER = 1341 350 | FPARSER_EOF_IN_COMMENT = 1342 351 | FPARSER_ERROR_IN_PARAMETER = 1343 352 | FPARSER_EOF_IN_UNKNOWN_PARAMETER = 1344 353 | VIEW_NO_EXPLAIN = 1345 354 | FRM_UNKNOWN_TYPE = 1346 355 | WRONG_OBJECT = 1347 356 | NONUPDATEABLE_COLUMN = 1348 357 | VIEW_SELECT_DERIVED = 1349 358 | VIEW_SELECT_CLAUSE = 1350 359 | VIEW_SELECT_VARIABLE = 1351 360 | VIEW_SELECT_TMPTABLE = 1352 361 | VIEW_WRONG_LIST = 1353 362 | WARN_VIEW_MERGE = 1354 363 | WARN_VIEW_WITHOUT_KEY = 1355 364 | VIEW_INVALID = 1356 365 | SP_NO_DROP_SP = 1357 366 | SP_GOTO_IN_HNDLR = 1358 367 | TRG_ALREADY_EXISTS = 1359 368 | TRG_DOES_NOT_EXIST = 1360 369 | TRG_ON_VIEW_OR_TEMP_TABLE = 1361 370 | TRG_CANT_CHANGE_ROW = 1362 371 | TRG_NO_SUCH_ROW_IN_TRG = 1363 372 | NO_DEFAULT_FOR_FIELD = 1364 373 | DIVISION_BY_ZERO = 1365 374 | TRUNCATED_WRONG_VALUE_FOR_FIELD = 1366 375 | ILLEGAL_VALUE_FOR_TYPE = 1367 376 | VIEW_NONUPD_CHECK = 1368 377 | VIEW_CHECK_FAILED = 1369 378 | PROCACCESS_DENIED_ERROR = 1370 379 | RELAY_LOG_FAIL = 1371 380 | PASSWD_LENGTH = 1372 381 | UNKNOWN_TARGET_BINLOG = 1373 382 | IO_ERR_LOG_INDEX_READ = 1374 383 | BINLOG_PURGE_PROHIBITED = 1375 384 | FSEEK_FAIL = 1376 385 | BINLOG_PURGE_FATAL_ERR = 1377 386 | LOG_IN_USE = 1378 387 | LOG_PURGE_UNKNOWN_ERR = 1379 388 | RELAY_LOG_INIT = 1380 389 | NO_BINARY_LOGGING = 1381 390 | RESERVED_SYNTAX = 1382 391 | WSAS_FAILED = 1383 392 | DIFF_GROUPS_PROC = 1384 393 | NO_GROUP_FOR_PROC = 1385 394 | ORDER_WITH_PROC = 1386 395 | LOGGING_PROHIBIT_CHANGING_OF = 1387 396 | NO_FILE_MAPPING = 1388 397 | WRONG_MAGIC = 1389 398 | PS_MANY_PARAM = 1390 399 | KEY_PART_0 = 1391 400 | VIEW_CHECKSUM = 1392 401 | VIEW_MULTIUPDATE = 1393 402 | VIEW_NO_INSERT_FIELD_LIST = 1394 403 | VIEW_DELETE_MERGE_VIEW = 1395 404 | CANNOT_USER = 1396 405 | XAER_NOTA = 1397 406 | XAER_INVAL = 1398 407 | XAER_RMFAIL = 1399 408 | XAER_OUTSIDE = 1400 409 | XAER_RMERR = 1401 410 | XA_RBROLLBACK = 1402 411 | NONEXISTING_PROC_GRANT = 1403 412 | PROC_AUTO_GRANT_FAIL = 1404 413 | PROC_AUTO_REVOKE_FAIL = 1405 414 | DATA_TOO_LONG = 1406 415 | SP_BAD_SQLSTATE = 1407 416 | STARTUP = 1408 417 | LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR = 1409 418 | CANT_CREATE_USER_WITH_GRANT = 1410 419 | WRONG_VALUE_FOR_TYPE = 1411 420 | TABLE_DEF_CHANGED = 1412 421 | SP_DUP_HANDLER = 1413 422 | SP_NOT_VAR_ARG = 1414 423 | SP_NO_RETSET = 1415 424 | CANT_CREATE_GEOMETRY_OBJECT = 1416 425 | FAILED_ROUTINE_BREAK_BINLOG = 1417 426 | BINLOG_UNSAFE_ROUTINE = 1418 427 | BINLOG_CREATE_ROUTINE_NEED_SUPER = 1419 428 | EXEC_STMT_WITH_OPEN_CURSOR = 1420 429 | STMT_HAS_NO_OPEN_CURSOR = 1421 430 | COMMIT_NOT_ALLOWED_IN_SF_OR_TRG = 1422 431 | NO_DEFAULT_FOR_VIEW_FIELD = 1423 432 | SP_NO_RECURSION = 1424 433 | TOO_BIG_SCALE = 1425 434 | TOO_BIG_PRECISION = 1426 435 | M_BIGGER_THAN_D = 1427 436 | WRONG_LOCK_OF_SYSTEM_TABLE = 1428 437 | CONNECT_TO_FOREIGN_DATA_SOURCE = 1429 438 | QUERY_ON_FOREIGN_DATA_SOURCE = 1430 439 | FOREIGN_DATA_SOURCE_DOESNT_EXIST = 1431 440 | FOREIGN_DATA_STRING_INVALID_CANT_CREATE = 1432 441 | FOREIGN_DATA_STRING_INVALID = 1433 442 | CANT_CREATE_FEDERATED_TABLE = 1434 443 | TRG_IN_WRONG_SCHEMA = 1435 444 | STACK_OVERRUN_NEED_MORE = 1436 445 | TOO_LONG_BODY = 1437 446 | WARN_CANT_DROP_DEFAULT_KEYCACHE = 1438 447 | TOO_BIG_DISPLAYWIDTH = 1439 448 | XAER_DUPID = 1440 449 | DATETIME_FUNCTION_OVERFLOW = 1441 450 | CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG = 1442 451 | VIEW_PREVENT_UPDATE = 1443 452 | PS_NO_RECURSION = 1444 453 | SP_CANT_SET_AUTOCOMMIT = 1445 454 | MALFORMED_DEFINER = 1446 455 | VIEW_FRM_NO_USER = 1447 456 | VIEW_OTHER_USER = 1448 457 | NO_SUCH_USER = 1449 458 | FORBID_SCHEMA_CHANGE = 1450 459 | ROW_IS_REFERENCED_2 = 1451 460 | NO_REFERENCED_ROW_2 = 1452 461 | SP_BAD_VAR_SHADOW = 1453 462 | TRG_NO_DEFINER = 1454 463 | OLD_FILE_FORMAT = 1455 464 | SP_RECURSION_LIMIT = 1456 465 | SP_PROC_TABLE_CORRUPT = 1457 466 | ERROR_LAST = 1457 467 | 468 | --------------------------------------------------------------------------------