def _multipleStatement(self, stream, methodName): def applyMethod(stmts, methodName): @_transaction def method(self, **kwargs): for stmt in stmts: self.cursor.execute(stmt, kwargs) setattr(self.__class__, methodName, method) applyMethod([unicode(x) for x in split2(stream)], methodName)
def parse_string(self, sql, method_name, dir_path='sql', bypass_types=False, lazy=False): """ Build a function from a string containing a SQL query Also add the function as a method to the AntiORM class :param sql: the SQL code of the method to be parsed :type sql: string :param method_name: the name of the method :type method_name: string :param dir_path: path to the dir with the SQL files (for INCLUDE) :type dir_path: string :param bypass_types: set if parsing should bypass types :type bypass_types: boolean :param lazy: set if parsing should be postpone until required :type lazy: boolean :return: the parsed function or None if `lazy` is True :rtype: function or None """ # Lazy processing, store data & only do the parse if later is required if lazy: self._lazy[method_name] = (self.parse_string, sql, dir_path, bypass_types) return # Disable by-pass of types if not using CPython compatible bytecode if bypass_types and not _getframe: warn(RuntimeWarning("Can't acces to stack. " "Disabling by-pass of types.")) bypass_types = False # Set the dirpaths where to look for the INCLUDE statements dirpaths = self._dirpaths if dir_path not in dirpaths: dirpaths.append(dir_path) pipe = Pipeline() pipe.append(tokenize) pipe.append(IncludeStatement(dirpaths)) stream = compact(pipe(sql.strip())) # One statement query if len(split2(stream)) == 1: return self._one_statement(method_name, stream, bypass_types) # Multiple statement query return self._multiple_statement(method_name, stream, bypass_types)
def _statement_INSERT(self, stream, methodName): "Special case because we are interested in get inserted row id" stmts = split2(stream) # One statement query if len(stmts) == 1: def applyMethod(sql, methodName): @_transaction def method(self, **kwargs): self.cursor.execute(sql, kwargs) return self.cursor.lastrowid setattr(self.__class__, methodName, method) sql = unicode(stmts[0]) # Multiple statement query (return last row id of first one) else: def applyMethod(stmts, methodName): @_transaction def method(self, _=None, **kwargs): # Received un-named parameter, it would be a iterable if _ != None: # Parameters are given as a dictionary, # put them in the correct place (bad guy...) if isinstance(_, dict): kwargs = _ # Iterable of parameters, execute as normal else: for kwargs in _: for stmt in stmts: self.cursor.execute(stmt, kwargs) return self.cursor.execute(stmts[0], kwargs) rowid = self.cursor.lastrowid for stmt in stmts[1:]: self.cursor.execute(stmt, kwargs) return rowid setattr(self.__class__, methodName, method) sql = [unicode(x) for x in stmts] applyMethod(sql, methodName)
def ParseString(self, sql, methodName, includePath='sql'): "Build a function from a string containing a SQL query" stream = Compact(sql, includePath) # Insert statement (return last row id) if IsType('INSERT')(stream): self._statement_INSERT(stream, methodName) # One statement query elif len(split2(stream)) == 1: self._oneStatement(stream, methodName) # Multiple statement query else: self._multipleStatement(stream, methodName)
def _multiple_statement(self, method_name, stream, bypass_types): """ Route to the correct optimized function for multiple statements queries :param method_name: the name of the method :type method_name: string :param stream: the stream of tokens :type stream: iterable of tokens :param bypass_types: set if parsing should bypass types :type bypass_types: boolean """ stmts = map(unicode, split2(stream)) if self._paramstyle: stmts = map(self._paramstyle, stmts) # Insert statement (return last row id) if IsType('INSERT')(stream): return self._multiple_statement_INSERT(method_name, stmts, bypass_types) # Standard multiple statement query return self._multiple_statement_standard(method_name, stmts, bypass_types)